velocity-python 0.0.131__py3-none-any.whl → 0.0.134__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of velocity-python might be problematic. Click here for more details.

Files changed (88) hide show
  1. velocity/__init__.py +1 -1
  2. velocity/app/tests/__init__.py +1 -0
  3. velocity/app/tests/test_email_processing.py +112 -0
  4. velocity/app/tests/test_payment_profile_sorting.py +191 -0
  5. velocity/app/tests/test_spreadsheet_functions.py +124 -0
  6. velocity/aws/tests/__init__.py +1 -0
  7. velocity/aws/tests/test_lambda_handler_json_serialization.py +120 -0
  8. velocity/aws/tests/test_response.py +163 -0
  9. velocity/db/core/decorators.py +20 -3
  10. velocity/db/core/engine.py +33 -7
  11. velocity/db/exceptions.py +7 -0
  12. velocity/db/servers/base/__init__.py +9 -0
  13. velocity/db/servers/base/initializer.py +70 -0
  14. velocity/db/servers/base/operators.py +98 -0
  15. velocity/db/servers/base/sql.py +503 -0
  16. velocity/db/servers/base/types.py +135 -0
  17. velocity/db/servers/mysql/__init__.py +73 -0
  18. velocity/db/servers/mysql/operators.py +54 -0
  19. velocity/db/servers/{mysql_reserved.py → mysql/reserved.py} +2 -14
  20. velocity/db/servers/mysql/sql.py +569 -0
  21. velocity/db/servers/mysql/types.py +107 -0
  22. velocity/db/servers/postgres/__init__.py +52 -2
  23. velocity/db/servers/postgres/operators.py +34 -0
  24. velocity/db/servers/postgres/sql.py +4 -3
  25. velocity/db/servers/postgres/types.py +88 -2
  26. velocity/db/servers/sqlite/__init__.py +61 -0
  27. velocity/db/servers/sqlite/operators.py +52 -0
  28. velocity/db/servers/sqlite/reserved.py +20 -0
  29. velocity/db/servers/sqlite/sql.py +530 -0
  30. velocity/db/servers/sqlite/types.py +92 -0
  31. velocity/db/servers/sqlserver/__init__.py +73 -0
  32. velocity/db/servers/sqlserver/operators.py +47 -0
  33. velocity/db/servers/sqlserver/reserved.py +32 -0
  34. velocity/db/servers/sqlserver/sql.py +625 -0
  35. velocity/db/servers/sqlserver/types.py +114 -0
  36. velocity/db/tests/__init__.py +1 -0
  37. velocity/db/tests/common_db_test.py +0 -0
  38. velocity/db/tests/postgres/__init__.py +1 -0
  39. velocity/db/tests/postgres/common.py +49 -0
  40. velocity/db/tests/postgres/test_column.py +29 -0
  41. velocity/db/tests/postgres/test_connections.py +25 -0
  42. velocity/db/tests/postgres/test_database.py +21 -0
  43. velocity/db/tests/postgres/test_engine.py +205 -0
  44. velocity/db/tests/postgres/test_general_usage.py +88 -0
  45. velocity/db/tests/postgres/test_imports.py +8 -0
  46. velocity/db/tests/postgres/test_result.py +19 -0
  47. velocity/db/tests/postgres/test_row.py +137 -0
  48. velocity/db/tests/postgres/test_schema_locking.py +335 -0
  49. velocity/db/tests/postgres/test_schema_locking_unit.py +115 -0
  50. velocity/db/tests/postgres/test_sequence.py +34 -0
  51. velocity/db/tests/postgres/test_table.py +101 -0
  52. velocity/db/tests/postgres/test_transaction.py +106 -0
  53. velocity/db/tests/sql/__init__.py +1 -0
  54. velocity/db/tests/sql/common.py +177 -0
  55. velocity/db/tests/sql/test_postgres_select_advanced.py +285 -0
  56. velocity/db/tests/sql/test_postgres_select_variances.py +517 -0
  57. velocity/db/tests/test_cursor_rowcount_fix.py +150 -0
  58. velocity/db/tests/test_db_utils.py +221 -0
  59. velocity/db/tests/test_postgres.py +212 -0
  60. velocity/db/tests/test_postgres_unchanged.py +81 -0
  61. velocity/db/tests/test_process_error_robustness.py +292 -0
  62. velocity/db/tests/test_result_caching.py +279 -0
  63. velocity/db/tests/test_result_sql_aware.py +117 -0
  64. velocity/db/tests/test_row_get_missing_column.py +72 -0
  65. velocity/db/tests/test_schema_locking_initializers.py +226 -0
  66. velocity/db/tests/test_schema_locking_simple.py +97 -0
  67. velocity/db/tests/test_sql_builder.py +165 -0
  68. velocity/db/tests/test_tablehelper.py +486 -0
  69. velocity/misc/tests/__init__.py +1 -0
  70. velocity/misc/tests/test_db.py +90 -0
  71. velocity/misc/tests/test_fix.py +78 -0
  72. velocity/misc/tests/test_format.py +64 -0
  73. velocity/misc/tests/test_iconv.py +203 -0
  74. velocity/misc/tests/test_merge.py +82 -0
  75. velocity/misc/tests/test_oconv.py +144 -0
  76. velocity/misc/tests/test_original_error.py +52 -0
  77. velocity/misc/tests/test_timer.py +74 -0
  78. {velocity_python-0.0.131.dist-info → velocity_python-0.0.134.dist-info}/METADATA +1 -1
  79. velocity_python-0.0.134.dist-info/RECORD +125 -0
  80. velocity/db/servers/mysql.py +0 -640
  81. velocity/db/servers/sqlite.py +0 -968
  82. velocity/db/servers/sqlite_reserved.py +0 -208
  83. velocity/db/servers/sqlserver.py +0 -921
  84. velocity/db/servers/sqlserver_reserved.py +0 -314
  85. velocity_python-0.0.131.dist-info/RECORD +0 -62
  86. {velocity_python-0.0.131.dist-info → velocity_python-0.0.134.dist-info}/WHEEL +0 -0
  87. {velocity_python-0.0.131.dist-info → velocity_python-0.0.134.dist-info}/licenses/LICENSE +0 -0
  88. {velocity_python-0.0.131.dist-info → velocity_python-0.0.134.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,221 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Tests for database utility functions.
4
+ """
5
+
6
+ import unittest
7
+ from src.velocity.db.utils import (
8
+ safe_sort_key_none_last,
9
+ safe_sort_key_none_first,
10
+ safe_sort_key_with_default,
11
+ safe_sort_rows,
12
+ group_by_fields,
13
+ safe_sort_grouped_rows,
14
+ )
15
+
16
+
17
+ class TestDatabaseUtils(unittest.TestCase):
18
+ """Test database utility functions."""
19
+
20
+ def setUp(self):
21
+ """Set up test data."""
22
+ self.sample_data = [
23
+ {"id": 1, "name": "Alice", "date": "2024-03", "amount": 100},
24
+ {"id": 2, "name": "Bob", "date": None, "amount": 200},
25
+ {"id": 3, "name": "Charlie", "date": "2024-01", "amount": None},
26
+ {"id": 4, "name": "David", "date": "2024-02", "amount": 150},
27
+ {"id": 5, "name": "Eve", "date": None, "amount": 300},
28
+ ]
29
+
30
+ def test_safe_sort_key_none_last(self):
31
+ """Test sorting with None values at the end."""
32
+ sort_key = safe_sort_key_none_last("date")
33
+ sorted_data = sorted(self.sample_data, key=sort_key)
34
+
35
+ dates = [row["date"] for row in sorted_data]
36
+ expected = ["2024-01", "2024-02", "2024-03", None, None]
37
+ self.assertEqual(dates, expected)
38
+
39
+ def test_safe_sort_key_none_first(self):
40
+ """Test sorting with None values at the beginning."""
41
+ sort_key = safe_sort_key_none_first("date")
42
+ sorted_data = sorted(self.sample_data, key=sort_key)
43
+
44
+ dates = [row["date"] for row in sorted_data]
45
+ expected = [None, None, "2024-01", "2024-02", "2024-03"]
46
+ self.assertEqual(dates, expected)
47
+
48
+ def test_safe_sort_key_with_default(self):
49
+ """Test sorting with None values replaced by default."""
50
+ sort_key = safe_sort_key_with_default("date", "1900-01")
51
+ sorted_data = sorted(self.sample_data, key=sort_key)
52
+
53
+ dates = [row["date"] for row in sorted_data]
54
+ expected = [None, None, "2024-01", "2024-02", "2024-03"]
55
+ self.assertEqual(dates, expected)
56
+
57
+ def test_safe_sort_rows_none_last(self):
58
+ """Test safe_sort_rows with none_handling='last'."""
59
+ sorted_data = safe_sort_rows(self.sample_data, "date", none_handling="last")
60
+
61
+ dates = [row["date"] for row in sorted_data]
62
+ expected = ["2024-01", "2024-02", "2024-03", None, None]
63
+ self.assertEqual(dates, expected)
64
+
65
+ def test_safe_sort_rows_none_first(self):
66
+ """Test safe_sort_rows with none_handling='first'."""
67
+ sorted_data = safe_sort_rows(self.sample_data, "date", none_handling="first")
68
+
69
+ dates = [row["date"] for row in sorted_data]
70
+ expected = [None, None, "2024-01", "2024-02", "2024-03"]
71
+ self.assertEqual(dates, expected)
72
+
73
+ def test_safe_sort_rows_with_default(self):
74
+ """Test safe_sort_rows with none_handling='default'."""
75
+ sorted_data = safe_sort_rows(
76
+ self.sample_data, "date", none_handling="default", default_value="1900-01"
77
+ )
78
+
79
+ dates = [row["date"] for row in sorted_data]
80
+ expected = [None, None, "2024-01", "2024-02", "2024-03"]
81
+ self.assertEqual(dates, expected)
82
+
83
+ def test_safe_sort_rows_reverse(self):
84
+ """Test safe_sort_rows with reverse=True."""
85
+ sorted_data = safe_sort_rows(self.sample_data, "date", reverse=True)
86
+
87
+ dates = [row["date"] for row in sorted_data]
88
+ expected = [None, None, "2024-03", "2024-02", "2024-01"]
89
+ self.assertEqual(dates, expected)
90
+
91
+ def test_safe_sort_rows_invalid_none_handling(self):
92
+ """Test safe_sort_rows with invalid none_handling option."""
93
+ with self.assertRaises(ValueError) as context:
94
+ safe_sort_rows(self.sample_data, "date", none_handling="invalid")
95
+
96
+ self.assertIn("Invalid none_handling option", str(context.exception))
97
+
98
+ def test_group_by_fields_single_field(self):
99
+ """Test grouping by a single field."""
100
+ # Add data with same names for grouping
101
+ test_data = [
102
+ {"name": "Alice", "type": "A", "value": 1},
103
+ {"name": "Bob", "type": "B", "value": 2},
104
+ {"name": "Alice", "type": "C", "value": 3},
105
+ {"name": "Bob", "type": "A", "value": 4},
106
+ ]
107
+
108
+ groups = group_by_fields(test_data, "name")
109
+
110
+ self.assertEqual(len(groups), 2)
111
+ self.assertIn(("Alice",), groups)
112
+ self.assertIn(("Bob",), groups)
113
+ self.assertEqual(len(groups[("Alice",)]), 2)
114
+ self.assertEqual(len(groups[("Bob",)]), 2)
115
+
116
+ def test_group_by_fields_multiple_fields(self):
117
+ """Test grouping by multiple fields."""
118
+ test_data = [
119
+ {"name": "Alice", "type": "A", "value": 1},
120
+ {"name": "Bob", "type": "B", "value": 2},
121
+ {"name": "Alice", "type": "A", "value": 3},
122
+ {"name": "Alice", "type": "B", "value": 4},
123
+ ]
124
+
125
+ groups = group_by_fields(test_data, "name", "type")
126
+
127
+ self.assertEqual(len(groups), 3)
128
+ self.assertIn(("Alice", "A"), groups)
129
+ self.assertIn(("Bob", "B"), groups)
130
+ self.assertIn(("Alice", "B"), groups)
131
+ self.assertEqual(len(groups[("Alice", "A")]), 2)
132
+ self.assertEqual(len(groups[("Bob", "B")]), 1)
133
+ self.assertEqual(len(groups[("Alice", "B")]), 1)
134
+
135
+ def test_safe_sort_grouped_rows(self):
136
+ """Test sorting rows within groups."""
137
+ # Create grouped data
138
+ test_data = [
139
+ {"group": "A", "date": "2024-03", "value": 1},
140
+ {"group": "A", "date": None, "value": 2},
141
+ {"group": "A", "date": "2024-01", "value": 3},
142
+ {"group": "B", "date": "2024-02", "value": 4},
143
+ {"group": "B", "date": None, "value": 5},
144
+ ]
145
+
146
+ groups = group_by_fields(test_data, "group")
147
+ sorted_groups = safe_sort_grouped_rows(groups, "date")
148
+
149
+ # Check group A is sorted correctly
150
+ group_a_dates = [row["date"] for row in sorted_groups[("A",)]]
151
+ expected_a = ["2024-01", "2024-03", None]
152
+ self.assertEqual(group_a_dates, expected_a)
153
+
154
+ # Check group B is sorted correctly
155
+ group_b_dates = [row["date"] for row in sorted_groups[("B",)]]
156
+ expected_b = ["2024-02", None]
157
+ self.assertEqual(group_b_dates, expected_b)
158
+
159
+ def test_payment_profile_scenario(self):
160
+ """Test the specific payment profile scenario that was failing."""
161
+ payment_profiles = [
162
+ {
163
+ "sys_id": 1,
164
+ "email_address": "test@example.com",
165
+ "card_number": "1234",
166
+ "expiration_date": "2024-12",
167
+ "status": "active",
168
+ },
169
+ {
170
+ "sys_id": 2,
171
+ "email_address": "test@example.com",
172
+ "card_number": "1234",
173
+ "expiration_date": "2024-06",
174
+ "status": "active",
175
+ },
176
+ {
177
+ "sys_id": 3,
178
+ "email_address": "test@example.com",
179
+ "card_number": "1234",
180
+ "expiration_date": None,
181
+ "status": "active",
182
+ },
183
+ {
184
+ "sys_id": 4,
185
+ "email_address": "other@example.com",
186
+ "card_number": "5678",
187
+ "expiration_date": "2025-01",
188
+ "status": "active",
189
+ },
190
+ {
191
+ "sys_id": 5,
192
+ "email_address": "other@example.com",
193
+ "card_number": "5678",
194
+ "expiration_date": None,
195
+ "status": "active",
196
+ },
197
+ ]
198
+
199
+ # Group by email and card number
200
+ groups = group_by_fields(payment_profiles, "email_address", "card_number")
201
+
202
+ # Sort each group by expiration date
203
+ sorted_groups = safe_sort_grouped_rows(groups, "expiration_date")
204
+
205
+ # Verify we can safely enumerate through each group
206
+ for group_key, group in sorted_groups.items():
207
+ for idx, row in enumerate(group):
208
+ # This should not raise any errors
209
+ self.assertIsInstance(idx, int)
210
+ self.assertIn("sys_id", row)
211
+ self.assertIn("expiration_date", row)
212
+
213
+ # Check specific group sorting
214
+ test_group = sorted_groups[("test@example.com", "1234")]
215
+ exp_dates = [row["expiration_date"] for row in test_group]
216
+ expected = ["2024-06", "2024-12", None]
217
+ self.assertEqual(exp_dates, expected)
218
+
219
+
220
+ if __name__ == "__main__":
221
+ unittest.main()
@@ -0,0 +1,212 @@
1
+ import unittest
2
+ import decimal
3
+ from velocity.db.servers.postgres.sql import SQL
4
+ from velocity.db.servers.tablehelper import TableHelper
5
+
6
+
7
+ class TestSQLModule(unittest.TestCase):
8
+ def test_quote_simple_identifier(self):
9
+ self.assertEqual(TableHelper.quote("test"), "test")
10
+
11
+ def test_quote_reserved_word(self):
12
+ self.assertEqual(TableHelper.quote("SELECT"), '"SELECT"')
13
+
14
+ def test_quote_with_special_characters(self):
15
+ self.assertEqual(TableHelper.quote("my/schema"), '"my/schema"')
16
+
17
+ def test_quote_dot_notation(self):
18
+ self.assertEqual(TableHelper.quote("my_table.my_column"), "my_table.my_column")
19
+
20
+ def test_quote_list_identifiers(self):
21
+ self.assertEqual(
22
+ TableHelper.quote(["test", "SELECT", "my_table"]),
23
+ ["test", '"SELECT"', "my_table"],
24
+ )
25
+
26
+ def test_make_where_simple_equality(self):
27
+ # Create a mock transaction and table helper
28
+ mock_tx = type("MockTx", (), {})()
29
+ helper = TableHelper(mock_tx, "test_table")
30
+
31
+ sql, vals = helper.make_where({"column1": "value1"})
32
+ self.assertIn("column1 = %s", sql)
33
+ self.assertEqual(vals, ("value1",))
34
+
35
+ def test_make_where_with_null(self):
36
+ mock_tx = type("MockTx", (), {})()
37
+ helper = TableHelper(mock_tx, "test_table")
38
+
39
+ sql, vals = helper.make_where({"column1": None})
40
+ self.assertIn("column1 is NULL", sql)
41
+ self.assertEqual(vals, ())
42
+
43
+ def test_make_where_with_not_null(self):
44
+ mock_tx = type("MockTx", (), {})()
45
+ helper = TableHelper(mock_tx, "test_table")
46
+
47
+ sql, vals = helper.make_where({"column1!": None})
48
+ self.assertIn("column1 is not NULL", sql)
49
+ self.assertEqual(vals, ())
50
+
51
+ def test_make_where_with_operators(self):
52
+ mock_tx = type("MockTx", (), {})()
53
+ helper = TableHelper(mock_tx, "test_table")
54
+
55
+ sql, vals = helper.make_where({"column1>": 10, "column2!": "value2"})
56
+ self.assertIn("column1 > %s", sql)
57
+ self.assertIn("column2 != %s", sql)
58
+ self.assertEqual(len(vals), 2)
59
+
60
+ def test_make_where_with_list(self):
61
+ mock_tx = type("MockTx", (), {})()
62
+ helper = TableHelper(mock_tx, "test_table")
63
+
64
+ sql, vals = helper.make_where({"column1": [1, 2, 3]})
65
+ self.assertIn("column1 in", sql.lower())
66
+ self.assertEqual(len(vals), 3)
67
+
68
+ def test_make_where_between(self):
69
+ mock_tx = type("MockTx", (), {})()
70
+ helper = TableHelper(mock_tx, "test_table")
71
+
72
+ sql, vals = helper.make_where({"column1><": [1, 10]})
73
+ self.assertIn("between", sql.lower())
74
+ self.assertEqual(len(vals), 2)
75
+
76
+ def test_sql_select_simple(self):
77
+ sql_query, params = SQL.select(columns="*", table="my_table")
78
+ self.assertEqual(sql_query, "SELECT * FROM my_table")
79
+ self.assertEqual(params, ())
80
+
81
+ def test_sql_select_with_where(self):
82
+ sql_query, params = SQL.select(columns="*", table="my_table", where={"id": 1})
83
+ self.assertEqual(sql_query, "SELECT * FROM my_table WHERE id = %s")
84
+ self.assertEqual(params, (1,))
85
+
86
+ def test_sql_select_with_order_by(self):
87
+ sql_query, params = SQL.select(columns="*", table="my_table", orderby="id DESC")
88
+ self.assertEqual(sql_query, "SELECT * FROM my_table ORDER BY id DESC")
89
+ self.assertEqual(params, ())
90
+
91
+ def test_sql_insert(self):
92
+ sql_query, params = SQL.insert(
93
+ table="my_table", data={"column1": "value1", "column2": 2}
94
+ )
95
+ self.assertEqual(
96
+ sql_query, "INSERT INTO my_table (column1,column2) VALUES (%s,%s)"
97
+ )
98
+ self.assertEqual(params, ("value1", 2))
99
+
100
+ def test_sql_update(self):
101
+ sql_query, params = SQL.update(
102
+ table="my_table", data={"column1": "new_value"}, pk={"id": 1}
103
+ )
104
+ self.assertEqual(sql_query, "UPDATE my_table SET column1 = %s WHERE id = %s")
105
+ self.assertEqual(params, ("new_value", 1))
106
+
107
+ def test_sql_delete(self):
108
+ sql_query, params = SQL.delete(table="my_table", where={"id": 1})
109
+ self.assertEqual(sql_query, "DELETE FROM my_table WHERE id = %s")
110
+ self.assertEqual(params, (1,))
111
+
112
+ def test_sql_create_table(self):
113
+ sql_query, params = SQL.create_table(
114
+ name="public.test_table", columns={"name": str, "age": int}, drop=True
115
+ )
116
+ self.assertIn("CREATE TABLE public.test_table", sql_query)
117
+ self.assertIn("DROP TABLE IF EXISTS public.test_table CASCADE;", sql_query)
118
+ self.assertEqual(params, ())
119
+
120
+ def test_sql_drop_table(self):
121
+ sql_query, params = SQL.drop_table("public.test_table")
122
+ self.assertEqual(sql_query, "drop table if exists public.test_table cascade;")
123
+ self.assertEqual(params, ())
124
+
125
+ def test_sql_create_index(self):
126
+ sql_query, params = SQL.create_index(
127
+ table="my_table", columns="column1", unique=True
128
+ )
129
+ self.assertIn("CREATE UNIQUE INDEX", sql_query)
130
+ self.assertIn("ON my_table (column1)", sql_query)
131
+ self.assertEqual(params, ())
132
+
133
+ def test_sql_drop_index(self):
134
+ sql_query, params = SQL.drop_index(table="my_table", columns="column1")
135
+ self.assertIn("DROP INDEX IF EXISTS", sql_query)
136
+ self.assertEqual(params, ())
137
+
138
+ def test_sql_foreign_key_creation(self):
139
+ sql_query, params = SQL.create_foreign_key(
140
+ table="child_table",
141
+ columns="parent_id",
142
+ key_to_table="parent_table",
143
+ key_to_columns="id",
144
+ )
145
+ self.assertIn("ALTER TABLE child_table ADD CONSTRAINT", sql_query)
146
+ self.assertIn(
147
+ "FOREIGN KEY (parent_id) REFERENCES parent_table (id);", sql_query
148
+ )
149
+ self.assertEqual(params, ())
150
+
151
+ def test_sql_merge_insert(self):
152
+ sql_query, params = SQL.merge(
153
+ table="my_table",
154
+ data={"column1": "value1"},
155
+ pk={"id": 1},
156
+ on_conflict_do_nothing=True,
157
+ on_conflict_update=False,
158
+ )
159
+ self.assertIn("INSERT INTO my_table", sql_query)
160
+ self.assertIn("ON CONFLICT (id) DO NOTHING", sql_query)
161
+ self.assertEqual(params, ("value1", 1))
162
+
163
+ def test_sql_merge_update(self):
164
+ sql_query, params = SQL.merge(
165
+ table="my_table",
166
+ data={"column1": "value1"},
167
+ pk={"id": 1},
168
+ on_conflict_do_nothing=False,
169
+ on_conflict_update=True,
170
+ )
171
+ self.assertIn("INSERT INTO my_table", sql_query)
172
+ self.assertIn("ON CONFLICT (id) DO UPDATE SET", sql_query)
173
+ self.assertEqual(params, ("value1", 1))
174
+
175
+ def test_get_type_mapping(self):
176
+ self.assertEqual(SQL.get_type("string"), "TEXT")
177
+ self.assertEqual(SQL.get_type(123), "BIGINT")
178
+ self.assertEqual(SQL.get_type(123.456), "NUMERIC(19, 6)")
179
+ self.assertEqual(SQL.get_type(True), "BOOLEAN")
180
+ self.assertEqual(SQL.get_type(None), "TEXT")
181
+
182
+ def test_py_type_mapping(self):
183
+ self.assertEqual(SQL.py_type("INTEGER"), int)
184
+ self.assertEqual(SQL.py_type("NUMERIC"), decimal.Decimal)
185
+ self.assertEqual(SQL.py_type("TEXT"), str)
186
+ self.assertEqual(SQL.py_type("BOOLEAN"), bool)
187
+
188
+ def test_sql_truncate(self):
189
+ sql_query, params = SQL.truncate("my_table")
190
+ self.assertEqual(sql_query, "truncate table my_table")
191
+ self.assertEqual(params, ())
192
+
193
+ def test_sql_create_view(self):
194
+ sql_query, params = SQL.create_view(
195
+ name="my_view", query="SELECT * FROM my_table", temp=True, silent=True
196
+ )
197
+ self.assertIn(
198
+ "CREATE OR REPLACE TEMPORARY VIEW my_view AS SELECT * FROM my_table",
199
+ sql_query,
200
+ )
201
+ self.assertEqual(params, ())
202
+
203
+ def test_sql_drop_view(self):
204
+ sql_query, params = SQL.drop_view(name="my_view", silent=True)
205
+ self.assertEqual(sql_query, "DROP VIEW IF EXISTS my_view")
206
+ self.assertEqual(params, ())
207
+
208
+ # Additional tests can be added here to cover more methods and edge cases
209
+
210
+
211
+ if __name__ == "__main__":
212
+ unittest.main()
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Quick test to verify PostgreSQL implementation is functionally unchanged.
4
+ """
5
+ import sys
6
+ import os
7
+ sys.path.insert(0, '/home/ubuntu/tenspace/velocity-python/src')
8
+
9
+ def test_postgres_unchanged():
10
+ """Test that PostgreSQL implementation is functionally unchanged."""
11
+ print("Testing PostgreSQL implementation...")
12
+
13
+ # Test imports
14
+ try:
15
+ from velocity.db.servers.postgres import initialize
16
+ from velocity.db.servers.postgres.sql import SQL
17
+ from velocity.db.servers.postgres.types import TYPES
18
+ from velocity.db.servers.postgres.operators import OPERATORS
19
+ print("✓ All imports successful")
20
+ except ImportError as e:
21
+ print(f"✗ Import failed: {e}")
22
+ return False
23
+
24
+ # Test SQL class attributes are the same
25
+ expected_server = "PostGreSQL"
26
+ if SQL.server != expected_server:
27
+ print(f"✗ SQL.server changed: expected '{expected_server}', got '{SQL.server}'")
28
+ return False
29
+ print("✓ SQL.server unchanged")
30
+
31
+ # Test error codes are preserved
32
+ expected_duplicate_codes = ["23505"]
33
+ if SQL.DuplicateKeyErrorCodes != expected_duplicate_codes:
34
+ print(f"✗ DuplicateKeyErrorCodes changed: expected {expected_duplicate_codes}, got {SQL.DuplicateKeyErrorCodes}")
35
+ return False
36
+ print("✓ Error codes unchanged")
37
+
38
+ # Test TYPES class methods exist
39
+ if not hasattr(TYPES, 'get_type'):
40
+ print("✗ TYPES.get_type method missing")
41
+ return False
42
+ if not hasattr(TYPES, 'get_conv'):
43
+ print("✗ TYPES.get_conv method missing")
44
+ return False
45
+ if not hasattr(TYPES, 'py_type'):
46
+ print("✗ TYPES.py_type method missing")
47
+ return False
48
+ print("✓ TYPES methods present")
49
+
50
+ # Test type mappings are correct
51
+ if TYPES.get_type(str) != "TEXT":
52
+ print(f"✗ TYPES.get_type(str) changed: expected 'TEXT', got '{TYPES.get_type(str)}'")
53
+ return False
54
+ if TYPES.get_type(int) != "BIGINT":
55
+ print(f"✗ TYPES.get_type(int) changed: expected 'BIGINT', got '{TYPES.get_type(int)}'")
56
+ return False
57
+ print("✓ Type mappings unchanged")
58
+
59
+ # Test operators are preserved
60
+ if OPERATORS.get("<>") != "<>":
61
+ print(f"✗ Operator '<>' mapping changed")
62
+ return False
63
+ if OPERATORS.get("%%") != "ILIKE":
64
+ print(f"✗ Operator '%%' mapping changed")
65
+ return False
66
+ print("✓ Operators unchanged")
67
+
68
+ # Test SQL methods exist (just check key ones)
69
+ sql_methods = ['select', 'insert', 'update', 'delete', 'merge', 'version', 'databases']
70
+ for method in sql_methods:
71
+ if not hasattr(SQL, method):
72
+ print(f"✗ SQL.{method} method missing")
73
+ return False
74
+ print("✓ SQL methods present")
75
+
76
+ print("\n🎉 PostgreSQL implementation is functionally unchanged!")
77
+ return True
78
+
79
+ if __name__ == "__main__":
80
+ success = test_postgres_unchanged()
81
+ sys.exit(0 if success else 1)