From a35692142ecdc7c2e3f9572ced9e8a5a33cf6cdc Mon Sep 17 00:00:00 2001
From: Cezary Statkiewicz <cezary@baserow.io>
Date: Wed, 26 Mar 2025 15:20:57 +0100
Subject: [PATCH] 2213 tests

---
 .../contrib/database/fields/field_types.py    |   1 +
 .../file_import/test_file_import_tasks.py     | 313 ++++++++++++++++++
 .../database/file_import/upsert_base_data.csv |  20 ++
 .../file_import/upsert_base_data_list.json    |  62 ++++
 .../file_import/upsert_bool_data.json         | 118 +++++++
 .../file_import/upsert_boolean_date_data.json | 104 ++++++
 .../upsert_boolean_duration_data.json         | 104 ++++++
 .../upsert_boolean_timestamp_data.json        | 104 ++++++
 .../upsert_composed_data_list.json            |  62 ++++
 .../file_import/upsert_date_data.json         | 118 +++++++
 .../upsert_date_duration_data.json            | 104 ++++++
 .../upsert_date_timestamp_data.json           | 104 ++++++
 .../file_import/upsert_datetime_data.json     | 118 +++++++
 .../file_import/upsert_duration_data.json     | 118 +++++++
 .../file_import/upsert_email_data.json        | 118 +++++++
 .../file_import/upsert_long_text_data.json    | 117 +++++++
 .../upsert_number_boolean_data.json           | 104 ++++++
 .../file_import/upsert_number_data.json       | 117 +++++++
 .../file_import/upsert_number_date_data.json  | 104 ++++++
 .../upsert_number_duration_data.json          | 104 ++++++
 .../upsert_number_timestamp_data.json         | 104 ++++++
 .../file_import/upsert_phone_data.json        | 118 +++++++
 .../file_import/upsert_rating_data.json       | 117 +++++++
 .../file_import/upsert_text_boolean_data.json | 104 ++++++
 .../file_import/upsert_text_data.json         | 117 +++++++
 .../file_import/upsert_text_date_data.json    | 104 ++++++
 .../upsert_text_duration_data.json            | 104 ++++++
 .../file_import/upsert_text_number_data.json  | 104 ++++++
 .../upsert_text_timestamp_data.json           | 104 ++++++
 .../upsert_timestamp_duration_data.json       | 104 ++++++
 .../database/file_import/upsert_url_data.json | 118 +++++++
 31 files changed, 3312 insertions(+)
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_base_data.csv
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_base_data_list.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_bool_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_boolean_date_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_boolean_duration_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_boolean_timestamp_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_composed_data_list.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_date_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_date_duration_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_date_timestamp_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_datetime_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_duration_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_email_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_long_text_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_number_boolean_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_number_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_number_date_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_number_duration_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_number_timestamp_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_phone_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_rating_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_text_boolean_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_text_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_text_date_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_text_duration_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_text_number_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_text_timestamp_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_timestamp_duration_data.json
 create mode 100644 backend/tests/test_data/baserow/database/file_import/upsert_url_data.json

diff --git a/backend/src/baserow/contrib/database/fields/field_types.py b/backend/src/baserow/contrib/database/fields/field_types.py
index 0b83d2ffa..dfff82050 100755
--- a/backend/src/baserow/contrib/database/fields/field_types.py
+++ b/backend/src/baserow/contrib/database/fields/field_types.py
@@ -524,6 +524,7 @@ class URLFieldType(CollationSortMixin, TextFieldMatchingRegexFieldType):
     type = "url"
     model_class = URLField
     _can_group_by = True
+    can_upsert = True
 
     @property
     def regex(self):
diff --git a/backend/tests/baserow/contrib/database/file_import/test_file_import_tasks.py b/backend/tests/baserow/contrib/database/file_import/test_file_import_tasks.py
index bdcc29d0c..9e072917f 100644
--- a/backend/tests/baserow/contrib/database/file_import/test_file_import_tasks.py
+++ b/backend/tests/baserow/contrib/database/file_import/test_file_import_tasks.py
@@ -1,4 +1,6 @@
+import json
 from datetime import datetime, timedelta, timezone
+from typing import NamedTuple
 
 from django.conf import settings
 from django.test.utils import override_settings
@@ -27,6 +29,7 @@ from baserow.contrib.database.table.exceptions import (
     InitialTableDataLimitExceeded,
     InvalidInitialTableData,
 )
+from baserow.contrib.database.table.models import GeneratedTableModel
 from baserow.core.exceptions import UserNotInWorkspace
 from baserow.core.jobs.constants import (
     JOB_FAILED,
@@ -984,3 +987,313 @@ def test_run_file_import_task_with_upsert(data_fixture, patch_filefield_storage)
     last = rows[-2]
     assert getattr(last, f1.db_column) == "aab"
     assert getattr(last, f6.db_column) == "aab-1-3-new"
+
+
+class UpsertData(NamedTuple):
+    model: GeneratedTableModel
+    text_field: TextField
+    description: TextField
+
+
+def prepare_upsert_data(
+    data_fixture,
+    patch_filefield_storage,
+    open_test_file,
+    upsert_field_idx: list[int],
+    upsert_file_name: str | None,
+) -> UpsertData:
+    """
+    Helper function to create test model + data for upsert functionality.
+
+
+    :param data_fixture:
+    :param patch_filefield_storage:
+    :param open_test_file:
+    :param upsert_field_idx: a list of indexes of fields from `upsert_fields` list
+    :param upsert_file_name: file name part with test data for upsert functionality.
+        Full file name is calculated, and should contain almost-full file import
+        payload. Upsert fields configuration is updated in the code from
+        `upsert_field_idx`.
+    :return: UpsertData with context needed by upsert test
+    """
+
+    user = data_fixture.create_user()
+    database = data_fixture.create_database_application(user=user)
+    table = data_fixture.create_database_table(user=user, database=database)
+
+    with open_test_file(
+        "baserow/database/file_import/upsert_base_data_list.json", "rt"
+    ) as f:
+        init_data = json.load(f)
+
+    upsert_fields = [
+        data_fixture.create_text_field(table=table, name="Text"),
+        data_fixture.create_long_text_field(table=table, name="Long text"),
+        data_fixture.create_number_field(
+            table=table, name="Number", number_decimal_places=3
+        ),
+        data_fixture.create_rating_field(table=table, name="Rating"),
+        data_fixture.create_boolean_field(table=table, name="Boolean"),
+        data_fixture.create_date_field(table=table, name="Date"),
+        data_fixture.create_date_field(
+            table=table, date_include_time=True, name="Datetime"
+        ),
+        data_fixture.create_duration_field(
+            table=table, duration_format="d h", name="Duration"
+        ),
+        data_fixture.create_url_field(table=table, name="URL"),
+        data_fixture.create_phone_number_field(table=table, name="Phone number"),
+        data_fixture.create_email_field(table=table, name="Email"),
+    ]
+    text_field = upsert_fields[0]
+    single_select = data_fixture.create_single_select_field(
+        table=table, name="Single select"
+    )
+    for opt_value in ["aaa", "bbb", "ccc", "ddd"]:
+        data_fixture.create_select_option(field=single_select, value=opt_value)
+    description = data_fixture.create_long_text_field(table=table, name="Description")
+
+    model = table.get_model()
+
+    with patch_filefield_storage():
+        job = data_fixture.create_file_import_job(
+            data={"data": init_data[1:]},
+            table=table,
+            user=user,
+        )
+        run_async_job(job.id)
+        job.refresh_from_db()
+        assert job.finished
+
+    assert len(model.objects.all()) == len(init_data) - 1
+
+    upsert_fields = [upsert_fields[uidx] for uidx in upsert_field_idx]
+
+    # sanity check: field name should match
+    assert [u.name for u in upsert_fields] == [
+        init_data[0][uidx] for uidx in upsert_field_idx
+    ]
+
+    # upsert_file_name contains almost-full file import job structure. The only thing
+    # missing is configuration.upsert_fields, which is calculated in code from args.
+    with open_test_file(
+        f"baserow/database/file_import/upsert_{upsert_file_name}_data.json", "rt"
+    ) as f:
+        update_data = json.load(f)
+        update_data["configuration"]["upsert_fields"] = [u.id for u in upsert_fields]
+        with patch_filefield_storage():
+            job = data_fixture.create_file_import_job(
+                data=update_data,
+                table=table,
+                user=user,
+            )
+            run_async_job(job.id)
+            job.refresh_from_db()
+            assert job.finished
+
+    return UpsertData(model=model, text_field=text_field, description=description)
+
+
+@pytest.mark.parametrize(
+    "upsert_field_idx,upsert_file_name",
+    [
+        ((0,), "text"),
+        ((1,), "long_text"),
+        ((2,), "number"),
+        ((3,), "rating"),
+        ((4,), "bool"),
+        ((5,), "date"),
+        ((6,), "datetime"),
+        ((7,), "duration"),
+        ((8,), "url"),
+        ((9,), "phone"),
+        ((10,), "email"),
+    ],
+)
+@pytest.mark.django_db(transaction=True)
+def test_run_file_import_task_with_upsert_for_single_field_type(
+    data_fixture,
+    patch_filefield_storage,
+    open_test_file,
+    upsert_field_idx: list[int],
+    upsert_file_name: str | None,
+):
+    """
+    test upsert with single field types
+    """
+
+    # upsert_file_name contains a 6-element set:
+    # one value duplicated on import side: 1 update, 1 insert
+    # one value duplicated on both sides + 1 extra in import: 2 updates, 1 insert
+    # one value that doesn't have corresponding table value: 1 insert
+    prepared = prepare_upsert_data(
+        data_fixture,
+        patch_filefield_storage,
+        open_test_file,
+        upsert_field_idx,
+        upsert_file_name,
+    )
+
+    model, text_field, description = prepared
+
+    # aaa: one updated, one inserted
+    # bbb: two updated, one inserted
+    # zzz: one inserted
+    # updated: 3, inserted: 3
+    assert len(model.objects.all()) == 6
+    assert len(model.objects.filter(**{text_field.db_column: "aaa"})) == 2
+    assert len(model.objects.filter(**{text_field.db_column: "bbb"})) == 3
+    assert len(model.objects.filter(**{text_field.db_column: "zzz"})) == 1
+    assert len(model.objects.filter(**{description.db_column: "inserted zzz"})) == 1
+    assert len(model.objects.filter(**{description.db_column: "inserted aaa"})) == 1
+    assert len(model.objects.filter(**{description.db_column: "inserted bbb"})) == 1
+
+    assert len(model.objects.filter(**{description.db_column: "updated aaa"})) == 1
+    assert len(model.objects.filter(**{description.db_column: "updated bbb"})) == 2
+
+
+# test single fields and selected pairs
+@pytest.mark.parametrize(
+    "upsert_field_idx,upsert_file_name",
+    [
+        (
+            (
+                0,
+                2,
+            ),  # text + number
+            "text_number",
+        ),
+        (
+            (
+                0,
+                4,
+            ),  # text + boolean
+            "text_boolean",
+        ),
+        (
+            (
+                0,
+                5,
+            ),  # text + date
+            "text_date",
+        ),
+        (
+            (
+                0,
+                6,
+            ),
+            "text_timestamp",
+        ),  # text + timestamp
+        (
+            (
+                0,
+                7,
+            ),
+            "text_duration",
+        ),  # text + duration
+        (
+            (
+                2,
+                4,
+            ),
+            "number_boolean",
+        ),  # number + boolean
+        (
+            (
+                2,
+                5,
+            ),
+            "number_date",
+        ),  # number + date
+        (
+            (
+                2,
+                6,
+            ),
+            "number_timestamp",
+        ),  # number + timestamp
+        (
+            (
+                2,
+                7,
+            ),
+            "number_duration",
+        ),  # number + duration
+        (
+            (
+                4,
+                5,
+            ),
+            "boolean_date",
+        ),  # boolean + date
+        (
+            (
+                4,
+                6,
+            ),
+            "boolean_timestamp",
+        ),  # boolean + timestamp
+        (
+            (
+                4,
+                7,
+            ),
+            "boolean_duration",
+        ),  # boolean + duration
+        (
+            (
+                5,
+                6,
+            ),
+            "date_timestamp",
+        ),  # date +timestamp
+        (
+            (
+                5,
+                7,
+            ),
+            "date_duration",
+        ),  # date + duration
+        (
+            (6, 7),
+            "timestamp_duration",
+        ),  # timestamp + duration
+    ],
+)
+@pytest.mark.django_db(transaction=True)
+def test_run_file_import_task_with_upsert_for_multiple_field_types(
+    data_fixture,
+    patch_filefield_storage,
+    open_test_file,
+    upsert_field_idx: list[int],
+    upsert_file_name: str | None,
+):
+    # upsert_file_name contains 5-element update:
+    # one with duplicated on import side, that will produce 1 update + 1 insert
+    # one duplicated on table side, that will produce 1 update + 1 insert
+    # one new, that will produce 1 insert
+
+    prepared = prepare_upsert_data(
+        data_fixture,
+        patch_filefield_storage,
+        open_test_file,
+        upsert_field_idx,
+        upsert_file_name,
+    )
+
+    model, text_field, description = prepared
+
+    # aaa: one updated, one inserted
+    # bbb: one updated, one inserted
+    # zzz: one inserted
+    # updated: 2, inserted: 3
+    assert len(model.objects.all()) == 6
+    assert len(model.objects.filter(**{text_field.db_column: "aaa"})) == 2
+    assert len(model.objects.filter(**{text_field.db_column: "bbb"})) == 3
+    assert len(model.objects.filter(**{text_field.db_column: "zzz"})) == 1
+    assert len(model.objects.filter(**{description.db_column: "inserted zzz"})) == 1
+    assert len(model.objects.filter(**{description.db_column: "inserted aaa"})) == 1
+    assert len(model.objects.filter(**{description.db_column: "inserted bbb"})) == 1
+
+    assert len(model.objects.filter(**{description.db_column: "updated aaa"})) == 1
+    assert len(model.objects.filter(**{description.db_column: "updated bbb"})) == 1
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_base_data.csv b/backend/tests/test_data/baserow/database/file_import/upsert_base_data.csv
new file mode 100644
index 000000000..9cea2d0b9
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_base_data.csv
@@ -0,0 +1,20 @@
+Text,Long text,Number,Rating,Boolean,Date,Datetime,Duration,URL,Phone number,Email,Single select
+aaa,one,1.000,5,True,2021-01-03,2021-01-02 23:00,0d 4h,http://a.com,+1234,test1@email.com,aaa
+bbb,two,2.000,4,False,2025-03-03,2025-03-02 23:00,0d 2h,http://a.com,+123456,test1@email.com,aaa
+ccc,three,3.000,3,True,2025-03-09,2025-03-08 23:00,0d 3h,http://a.com,+12345,test1@email.com,aaa
+ddd,four,4.000,2,False,,,,http://b.com,123457,test1@email.com,aaa
+eee,five,5.000,1,True,2022-02-01,2022-01-31 23:00,0d 4h,http://b.com,,test1@email.com,aaa
+fff,six,6.000,5,False,2020-01-02,2020-01-01 23:00,0d 2h,http://c.com,2222223,test1@email.com,aaa
+ggg,seven,7.000,4,True,2021-01-03,2021-01-02 23:00,0d 3h,http://a.com,,test1@email.com,aaa
+hhh,eight,8.000,3,False,2022-02-01,2022-01-31 23:00,0d 12h,,+12345,test1@email.com,aaa
+iii,nine,9.000,2,True,,,0d 13h,http://a.com,+123456,test1@email.com,aaa
+jjj,one zero,10.000,1,False,,,0d 12h,http://b.com,+123457,test2@email.com,aaa
+kkk,one one,11.000,5,True,2019-08-17,2019-08-16 22:00,0d 14h,http://a.com,,test2@email.com,aaa
+lll,one two,12.000,4,False,2025-03-12,2025-03-11 23:00,0d 2h,http://a.com,+12345,test2@email.com,aaa
+mmm,one three,13.000,3,True,2019-08-17,2019-08-16 22:00,0d 2h,http://a.com,+12345,test2@email.com,aaa
+nnn,one four,14.000,2,False,2020-01-02,2020-01-01 23:00,,http://a.com,+12345,test2@email.com,aaa
+ooo,one five,15.000,1,True,,,,,,test2@email.com,aaa
+ppp,one six,16.000,5,False,,,,,,test2@email.com,aaa
+qqq,one seven,17.000,4,True,,,,,,test2@email.com,aaa
+rrr,one eight,18.000,3,False,,,,,,test2@email.com,aaa
+sss,one nine,19.000,2,True,,,,,,test2@email.com,aaa
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_base_data_list.json b/backend/tests/test_data/baserow/database/file_import/upsert_base_data_list.json
new file mode 100644
index 000000000..2a1f0fd04
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_base_data_list.json
@@ -0,0 +1,62 @@
+[
+  [
+    "Text",
+    "Long text",
+    "Number",
+    "Rating",
+    "Boolean",
+    "Date",
+    "Datetime",
+    "Duration",
+    "URL",
+    "Phone number",
+    "Email",
+    "Single select",
+    "Description"
+  ],
+  [
+    "aaa",
+    "one",
+    "1.000",
+    "5",
+    "True",
+    "2021-01-03",
+    "2021-01-02 23:00",
+    "0d 4h 29m 40s",
+    "http://a.com",
+    "+1234",
+    "test1@email.com",
+    "aaa",
+    "first aaa"
+  ],
+  [
+    "bbb",
+    "two",
+    "2.000",
+    "4",
+    "False",
+    "2025-03-03",
+    "2025-03-02 23:00",
+    "1:23:45",
+    "http://b.com/foo/bar",
+    "+123456",
+    "test2@email.com",
+    "aaa",
+    "first bbb"
+  ],
+  [
+    "bbb",
+    "two",
+    "2.000",
+    "4",
+    "False",
+    "2025-03-03",
+    "2025-03-02 23:00",
+    "1:23:45",
+    "http://b.com/foo/bar",
+    "+123456",
+    "test2@email.com",
+    "bbb",
+    "duplicated bbb"
+  ]
+]
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_bool_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_bool_data.json
new file mode 100644
index 000000000..b3212e683
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_bool_data.json
@@ -0,0 +1,118 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "aaa",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 2h",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "aaa",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 2h",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "aaa",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 2h",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "aaa",
+      "inserted bbb"
+    ],
+    [
+      "zzz",
+      "zzz",
+      "3.000",
+      "3",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 0m",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "aaa",
+      "inserted zzz"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        "true"
+      ],
+      [
+        "true"
+      ],
+      [
+        "false"
+      ],
+      [
+        "false"
+      ],
+      [
+        "false"
+      ],
+      [
+        "1"
+      ]
+    ]
+  }
+}
+
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_boolean_date_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_boolean_date_data.json
new file mode 100644
index 000000000..31701dd83
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_boolean_date_data.json
@@ -0,0 +1,104 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "bbb",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "zzz",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-02-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted zzz"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "ddd",
+      "inserted bbb"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        true,
+        "2021-01-03"
+      ],
+      [
+        "1",
+        "2021-01-03"
+      ],
+      [
+        "true",
+        "2021-02-03"
+      ],
+      [
+        false,
+        "2025-03-03"
+      ],
+      [
+        "0",
+        "2025-03-02"
+      ]
+    ]
+  }
+}
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_boolean_duration_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_boolean_duration_data.json
new file mode 100644
index 000000000..b0274f502
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_boolean_duration_data.json
@@ -0,0 +1,104 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "bbb",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "zzz",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-02-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted zzz"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-03 23:00",
+      "2:00",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "ddd",
+      "inserted bbb"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        true,
+        "0d 4h 29m 40s"
+      ],
+      [
+        "1",
+        "0d 4h 29m 40s"
+      ],
+      [
+        "true",
+        "0d 4h 29m 40s"
+      ],
+      [
+        "0",
+        "1:23:45"
+      ],
+      [
+        "false",
+        "2:00"
+      ]
+    ]
+  }
+}
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_boolean_timestamp_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_boolean_timestamp_data.json
new file mode 100644
index 000000000..0194971ea
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_boolean_timestamp_data.json
@@ -0,0 +1,104 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "bbb",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "zzz",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-02-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted zzz"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-03 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "ddd",
+      "inserted bbb"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        true,
+        "2021-01-02 23:00"
+      ],
+      [
+        "1",
+        "2021-01-02 23:00"
+      ],
+      [
+        "true",
+        "2021-01-02 23:00"
+      ],
+      [
+        "false",
+        "2025-03-02 23:00"
+      ],
+      [
+        false,
+        "2025-03-03 23:00"
+      ]
+    ]
+  }
+}
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_composed_data_list.json b/backend/tests/test_data/baserow/database/file_import/upsert_composed_data_list.json
new file mode 100644
index 000000000..2a1f0fd04
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_composed_data_list.json
@@ -0,0 +1,62 @@
+[
+  [
+    "Text",
+    "Long text",
+    "Number",
+    "Rating",
+    "Boolean",
+    "Date",
+    "Datetime",
+    "Duration",
+    "URL",
+    "Phone number",
+    "Email",
+    "Single select",
+    "Description"
+  ],
+  [
+    "aaa",
+    "one",
+    "1.000",
+    "5",
+    "True",
+    "2021-01-03",
+    "2021-01-02 23:00",
+    "0d 4h 29m 40s",
+    "http://a.com",
+    "+1234",
+    "test1@email.com",
+    "aaa",
+    "first aaa"
+  ],
+  [
+    "bbb",
+    "two",
+    "2.000",
+    "4",
+    "False",
+    "2025-03-03",
+    "2025-03-02 23:00",
+    "1:23:45",
+    "http://b.com/foo/bar",
+    "+123456",
+    "test2@email.com",
+    "aaa",
+    "first bbb"
+  ],
+  [
+    "bbb",
+    "two",
+    "2.000",
+    "4",
+    "False",
+    "2025-03-03",
+    "2025-03-02 23:00",
+    "1:23:45",
+    "http://b.com/foo/bar",
+    "+123456",
+    "test2@email.com",
+    "bbb",
+    "duplicated bbb"
+  ]
+]
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_date_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_date_data.json
new file mode 100644
index 000000000..6101f8401
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_date_data.json
@@ -0,0 +1,118 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "aaa",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 2h",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "aaa",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 2h",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "aaa",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 2h",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "aaa",
+      "inserted bbb"
+    ],
+    [
+      "zzz",
+      "zzz",
+      "3.000",
+      "3",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 0m",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "aaa",
+      "inserted zzz"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        "2021-01-03"
+      ],
+      [
+        "2021-01-03"
+      ],
+      [
+        "2025-03-03"
+      ],
+      [
+        "2025-03-03"
+      ],
+      [
+        "2025-03-03"
+      ],
+      [
+        "2025-03-01"
+      ]
+    ]
+  }
+}
+
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_date_duration_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_date_duration_data.json
new file mode 100644
index 000000000..e1867d38c
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_date_duration_data.json
@@ -0,0 +1,104 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "bbb",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "zzz",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-02-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted zzz"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-03 23:00",
+      "2:00",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "ddd",
+      "inserted bbb"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        "2021-01-03",
+        "0d 4h 29m 40s"
+      ],
+      [
+        "2021-01-03",
+        "0d 4h 29m 40s"
+      ],
+      [
+        "2021-02-03",
+        "0d 4h 29m 40s"
+      ],
+      [
+        "2025-03-03",
+        "1:23:45"
+      ],
+      [
+        "2025-03-03",
+        "2:00"
+      ]
+    ]
+  }
+}
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_date_timestamp_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_date_timestamp_data.json
new file mode 100644
index 000000000..7fb4e0e43
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_date_timestamp_data.json
@@ -0,0 +1,104 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "bbb",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "zzz",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-02-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted zzz"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-03 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "ddd",
+      "inserted bbb"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        "2021-01-03",
+        "2021-01-02 23:00"
+      ],
+      [
+        "2021-01-03",
+        "2021-01-02 23:00"
+      ],
+      [
+        "2021-02-03",
+        "2021-01-02 23:00"
+      ],
+      [
+        "2025-03-03",
+        "2025-03-02 23:00"
+      ],
+      [
+        "2025-03-03",
+        "2025-03-03 23:00"
+      ]
+    ]
+  }
+}
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_datetime_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_datetime_data.json
new file mode 100644
index 000000000..d56b04f41
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_datetime_data.json
@@ -0,0 +1,118 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "aaa",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 2h",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "aaa",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 2h",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "aaa",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 2h",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "aaa",
+      "inserted bbb"
+    ],
+    [
+      "zzz",
+      "zzz",
+      "3.000",
+      "3",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 0m",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "aaa",
+      "inserted zzz"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        "2021-01-02 23:00"
+      ],
+      [
+        "2021-01-02 23:00"
+      ],
+      [
+        "2025-03-02 23:00"
+      ],
+      [
+        "2025-03-02 23:00"
+      ],
+      [
+        "2025-03-02 23:00"
+      ],
+      [
+        "2025-03-02 23:01"
+      ]
+    ]
+  }
+}
+
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_duration_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_duration_data.json
new file mode 100644
index 000000000..9dc934957
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_duration_data.json
@@ -0,0 +1,118 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "bbb",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "ddd",
+      "inserted bbb"
+    ],
+    [
+      "zzz",
+      "zzz",
+      "3.000",
+      "3",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 0m",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "ddd",
+      "inserted zzz"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        "0d 4h 29m 40s"
+      ],
+      [
+        "0d 4h 29m 40s"
+      ],
+      [
+        "1:23:45"
+      ],
+      [
+        "1:23:45"
+      ],
+      [
+        "1:23:45"
+      ],
+      [
+        "100"
+      ]
+    ]
+  }
+}
+
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_email_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_email_data.json
new file mode 100644
index 000000000..5aa3933aa
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_email_data.json
@@ -0,0 +1,118 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "bbb",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "ddd",
+      "inserted bbb"
+    ],
+    [
+      "zzz",
+      "zzz",
+      "3.000",
+      "3",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 0m",
+      "http://foo.bar.com",
+      "54321000",
+      "foo@bar.com",
+      "aaa",
+      "inserted zzz"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        "test1@email.com"
+      ],
+      [
+        "test1@email.com"
+      ],
+      [
+        "test2@email.com"
+      ],
+      [
+        "test2@email.com"
+      ],
+      [
+        "test2@email.com"
+      ],
+      [
+        "foo@bar.com"
+      ]
+    ]
+  }
+}
+
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_long_text_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_long_text_data.json
new file mode 100644
index 000000000..ac760cfc8
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_long_text_data.json
@@ -0,0 +1,117 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "bbb",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ccc",
+      "inserted aaa"
+    ],
+    [
+      "bbb",
+      "two",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ccc",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ccc",
+      "inserted bbb"
+    ],
+    [
+      "zzz",
+      "end",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ccc",
+      "inserted zzz"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        "one"
+      ],
+      [
+        "one"
+      ],
+      [
+        "two"
+      ],
+      [
+        "two"
+      ],
+      [
+        "two"
+      ],
+      [
+        "end"
+      ]
+    ]
+  }
+}
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_number_boolean_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_number_boolean_data.json
new file mode 100644
index 000000000..925b8c722
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_number_boolean_data.json
@@ -0,0 +1,104 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "bbb",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "zzz",
+      "one",
+      "5.000",
+      "5",
+      "True",
+      "2021-02-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted zzz"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "True",
+      "2025-03-04",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "ddd",
+      "inserted bbb"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        "1",
+        true
+      ],
+      [
+        "1",
+        "true"
+      ],
+      [
+        "5",
+        "1"
+      ],
+      [
+        "2",
+        false
+      ],
+      [
+        "2",
+        1
+      ]
+    ]
+  }
+}
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_number_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_number_data.json
new file mode 100644
index 000000000..43c8589f7
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_number_data.json
@@ -0,0 +1,117 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "aaa",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 2h",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "aaa",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 2h",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "aaa",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 2h",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "aaa",
+      "inserted bbb"
+    ],
+    [
+      "zzz",
+      "zzz",
+      "3.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 0m",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "aaa",
+      "inserted zzz"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        "1.000"
+      ],
+      [
+        "1.000"
+      ],
+      [
+        "2.000"
+      ],
+      [
+        "2.000"
+      ],
+      [
+        "2.000"
+      ],
+      [
+        "3.000"
+      ]
+    ]
+  }
+}
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_number_date_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_number_date_data.json
new file mode 100644
index 000000000..a924c6e28
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_number_date_data.json
@@ -0,0 +1,104 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "bbb",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "zzz",
+      "one",
+      "5.000",
+      "5",
+      "True",
+      "2021-02-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted zzz"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-04",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "ddd",
+      "inserted bbb"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        1,
+        "2021-01-03"
+      ],
+      [
+        "1",
+        "2021-01-03"
+      ],
+      [
+        "5",
+        "2021-02-03"
+      ],
+      [
+        "2",
+        "2025-03-03"
+      ],
+      [
+        "2",
+        "2025-03-04"
+      ]
+    ]
+  }
+}
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_number_duration_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_number_duration_data.json
new file mode 100644
index 000000000..4bb888b6c
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_number_duration_data.json
@@ -0,0 +1,104 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "bbb",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "zzz",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-02-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted zzz"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-03 23:00",
+      "2:00",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "ddd",
+      "inserted bbb"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        1,
+        "0d 4h 29m 40s"
+      ],
+      [
+        "1",
+        "0d 4h 29m 40s"
+      ],
+      [
+        "5",
+        "0d 4h 29m 40s"
+      ],
+      [
+        2,
+        "1:23:45"
+      ],
+      [
+        "2",
+        "2:00"
+      ]
+    ]
+  }
+}
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_number_timestamp_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_number_timestamp_data.json
new file mode 100644
index 000000000..02fa95701
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_number_timestamp_data.json
@@ -0,0 +1,104 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "bbb",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "zzz",
+      "one",
+      "5.000",
+      "5",
+      "True",
+      "2021-02-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted zzz"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-04",
+      "2025-03-02 23:01",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "ddd",
+      "inserted bbb"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        1,
+        "2021-01-02 23:00"
+      ],
+      [
+        "1",
+        "2021-01-02 23:00"
+      ],
+      [
+        "5",
+        "2021-01-02 23:00"
+      ],
+      [
+        "2",
+        "2025-03-02 23:00"
+      ],
+      [
+        "2",
+        "2025-03-02 23:01"
+      ]
+    ]
+  }
+}
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_phone_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_phone_data.json
new file mode 100644
index 000000000..5500c017e
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_phone_data.json
@@ -0,0 +1,118 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "bbb",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "ddd",
+      "inserted bbb"
+    ],
+    [
+      "zzz",
+      "zzz",
+      "3.000",
+      "3",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 0m",
+      "http://foo.bar.com",
+      "54321000",
+      "test1@email.com",
+      "aaa",
+      "inserted zzz"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        "+1234"
+      ],
+      [
+        "+1234"
+      ],
+      [
+        "+123456"
+      ],
+      [
+        "+123456"
+      ],
+      [
+        "+123456"
+      ],
+      [
+        "54321000"
+      ]
+    ]
+  }
+}
+
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_rating_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_rating_data.json
new file mode 100644
index 000000000..48bb05e18
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_rating_data.json
@@ -0,0 +1,117 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "aaa",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 2h",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "aaa",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 2h",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "aaa",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 2h",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "aaa",
+      "inserted bbb"
+    ],
+    [
+      "zzz",
+      "zzz",
+      "3.000",
+      "3",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 0m",
+      "http://a.com",
+      "+123456",
+      "test1@email.com",
+      "aaa",
+      "inserted zzz"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        "5"
+      ],
+      [
+        "5"
+      ],
+      [
+        "4"
+      ],
+      [
+        "4"
+      ],
+      [
+        "4"
+      ],
+      [
+        "3"
+      ]
+    ]
+  }
+}
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_text_boolean_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_text_boolean_data.json
new file mode 100644
index 000000000..a8785da05
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_text_boolean_data.json
@@ -0,0 +1,104 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "bbb",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "zzz",
+      "one",
+      "5.000",
+      "5",
+      "True",
+      "2021-02-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted zzz"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "3.000",
+      "4",
+      "True",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "ddd",
+      "inserted bbb"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        "aaa",
+        "1"
+      ],
+      [
+        "aaa",
+        "1"
+      ],
+      [
+        "zzz",
+        "true"
+      ],
+      [
+        "bbb",
+        "false"
+      ],
+      [
+        "bbb",
+        "true"
+      ]
+    ]
+  }
+}
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_text_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_text_data.json
new file mode 100644
index 000000000..9fd6784e0
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_text_data.json
@@ -0,0 +1,117 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "bbb",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ccc",
+      "inserted aaa"
+    ],
+    [
+      "bbb",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ccc",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ccc",
+      "inserted bbb"
+    ],
+    [
+      "zzz",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ccc",
+      "inserted zzz"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        "aaa"
+      ],
+      [
+        "aaa"
+      ],
+      [
+        "bbb"
+      ],
+      [
+        "bbb"
+      ],
+      [
+        "bbb"
+      ],
+      [
+        "zzz"
+      ]
+    ]
+  }
+}
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_text_date_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_text_date_data.json
new file mode 100644
index 000000000..37c957f5c
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_text_date_data.json
@@ -0,0 +1,104 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "bbb",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "zzz",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-02-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted zzz"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "ddd",
+      "inserted bbb"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        "aaa",
+        "2021-01-03"
+      ],
+      [
+        "aaa",
+        "2021-01-03"
+      ],
+      [
+        "zzz",
+        "2021-02-03"
+      ],
+      [
+        "bbb",
+        "2025-03-03"
+      ],
+      [
+        "bbb",
+        "2025-03-02"
+      ]
+    ]
+  }
+}
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_text_duration_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_text_duration_data.json
new file mode 100644
index 000000000..f17630934
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_text_duration_data.json
@@ -0,0 +1,104 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "bbb",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "zzz",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-02-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted zzz"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-03 23:00",
+      "2:00",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "ddd",
+      "inserted bbb"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        "aaa",
+        "0d 4h 29m 40s"
+      ],
+      [
+        "aaa",
+        "0d 4h 29m 40s"
+      ],
+      [
+        "zzz",
+        "0d 4h 29m 40s"
+      ],
+      [
+        "bbb",
+        "1:23:45"
+      ],
+      [
+        "bbb",
+        "2:00"
+      ]
+    ]
+  }
+}
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_text_number_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_text_number_data.json
new file mode 100644
index 000000000..bd3a5fba2
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_text_number_data.json
@@ -0,0 +1,104 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "bbb",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "zzz",
+      "one",
+      "5.000",
+      "5",
+      "True",
+      "2021-02-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted zzz"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "3.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "ddd",
+      "inserted bbb"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        "aaa",
+        "1"
+      ],
+      [
+        "aaa",
+        "1"
+      ],
+      [
+        "zzz",
+        "5"
+      ],
+      [
+        "bbb",
+        "2"
+      ],
+      [
+        "bbb",
+        "3"
+      ]
+    ]
+  }
+}
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_text_timestamp_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_text_timestamp_data.json
new file mode 100644
index 000000000..a5efc3ca3
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_text_timestamp_data.json
@@ -0,0 +1,104 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "bbb",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "zzz",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-02-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted zzz"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-03 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "ddd",
+      "inserted bbb"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        "aaa",
+        "2021-01-02 23:00"
+      ],
+      [
+        "aaa",
+        "2021-01-02 23:00"
+      ],
+      [
+        "zzz",
+        "2021-01-02 23:00"
+      ],
+      [
+        "bbb",
+        "2025-03-02 23:00"
+      ],
+      [
+        "bbb",
+        "2025-03-03 23:00"
+      ]
+    ]
+  }
+}
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_timestamp_duration_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_timestamp_duration_data.json
new file mode 100644
index 000000000..69caca3d6
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_timestamp_duration_data.json
@@ -0,0 +1,104 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "bbb",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "zzz",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-02-03",
+      "2021-02-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted zzz"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "2:00",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "ddd",
+      "inserted bbb"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        "2021-01-02 23:00",
+        "0d 4h 29m 40s"
+      ],
+      [
+        "2021-01-02 23:00",
+        "0d 4h 29m 40s"
+      ],
+      [
+        "2021-02-02 23:00",
+        "0d 4h 29m 40s"
+      ],
+      [
+        "2025-03-02 23:00",
+        "1:23:45"
+      ],
+      [
+        "2025-03-02 23:00",
+        "2:00"
+      ]
+    ]
+  }
+}
diff --git a/backend/tests/test_data/baserow/database/file_import/upsert_url_data.json b/backend/tests/test_data/baserow/database/file_import/upsert_url_data.json
new file mode 100644
index 000000000..f4ca66816
--- /dev/null
+++ b/backend/tests/test_data/baserow/database/file_import/upsert_url_data.json
@@ -0,0 +1,118 @@
+{
+  "data": [
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "bbb",
+      "updated aaa"
+    ],
+    [
+      "aaa",
+      "one",
+      "1.000",
+      "5",
+      "True",
+      "2021-01-03",
+      "2021-01-02 23:00",
+      "0d 4h 29m 40s",
+      "http://a.com",
+      "+1234",
+      "test1@email.com",
+      "ddd",
+      "inserted aaa"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "bbb",
+      "updated bbb"
+    ],
+    [
+      "bbb",
+      "two",
+      "2.000",
+      "4",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "1:23:45",
+      "http://b.com/foo/bar",
+      "+123456",
+      "test2@email.com",
+      "ddd",
+      "inserted bbb"
+    ],
+    [
+      "zzz",
+      "zzz",
+      "3.000",
+      "3",
+      "False",
+      "2025-03-03",
+      "2025-03-02 23:00",
+      "0d 0m",
+      "http://foo.bar.com",
+      "+123456",
+      "test1@email.com",
+      "aaa",
+      "inserted zzz"
+    ]
+  ],
+  "configuration": {
+    "upsert_fields": [],
+    "upsert_values": [
+      [
+        "http://a.com"
+      ],
+      [
+        "http://a.com"
+      ],
+      [
+        "http://b.com/foo/bar"
+      ],
+      [
+        "http://b.com/foo/bar"
+      ],
+      [
+        "http://b.com/foo/bar"
+      ],
+      [
+        "http://foo.bar.com"
+      ]
+    ]
+  }
+}
+