commitdb 1.6.0__tar.gz → 2.0.0__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: commitdb
3
- Version: 1.6.0
3
+ Version: 2.0.0
4
4
  Summary: Python driver for CommitDB SQL Server
5
5
  Author: CommitDB Contributors
6
6
  License: Apache-2.0
@@ -62,6 +62,9 @@ with CommitDB('localhost', 3306) as db:
62
62
  # Insert data
63
63
  db.execute("INSERT INTO mydb.users (id, name, email) VALUES (1, 'Alice', 'alice@example.com')")
64
64
  db.execute("INSERT INTO mydb.users (id, name, email) VALUES (2, 'Bob', 'bob@example.com')")
65
+
66
+ # Bulk insert (multiple rows in one statement)
67
+ db.execute("INSERT INTO mydb.users (id, name, email) VALUES (3, 'Charlie', 'c@example.com'), (4, 'Diana', 'd@example.com')")
65
68
 
66
69
  # Query data - returns iterable of dictionaries
67
70
  result = db.query('SELECT * FROM mydb.users')
@@ -70,7 +73,32 @@ with CommitDB('localhost', 3306) as db:
70
73
  print(f" {row['id']}: {row['name']} ({row['email']})")
71
74
 
72
75
  # Use convenience methods
73
- db.insert('mydb', 'users', ['id', 'name', 'email'], [3, 'Charlie', 'charlie@example.com'])
76
+ db.insert('mydb', 'users', ['id', 'name', 'email'], [5, 'Eve', 'eve@example.com'])
77
+
78
+ # Use IN operator for multiple values
79
+ result = db.query("SELECT * FROM mydb.users WHERE id IN (1, 3)")
80
+
81
+ # Modify table schema
82
+ db.execute('ALTER TABLE mydb.users ADD COLUMN phone STRING')
83
+ db.execute('ALTER TABLE mydb.users RENAME COLUMN phone TO mobile')
84
+ db.execute('ALTER TABLE mydb.users DROP COLUMN mobile')
85
+
86
+ # Use string functions
87
+ result = db.query('SELECT UPPER(name) AS upper_name FROM mydb.users')
88
+ result = db.query("SELECT CONCAT(name, '@example.com') AS email FROM mydb.users")
89
+
90
+ # Use date functions
91
+ result = db.query('SELECT NOW() FROM mydb.users')
92
+ result = db.query("SELECT YEAR(created_at), MONTH(created_at) FROM mydb.events")
93
+
94
+ # Use JSON columns and functions
95
+ db.execute("CREATE TABLE mydb.docs (id INT PRIMARY KEY, data JSON)")
96
+ db.execute("INSERT INTO mydb.docs (id, data) VALUES (1, '{\"name\":\"Alice\"}')")
97
+ result = db.query("SELECT JSON_EXTRACT(data, '$.name') FROM mydb.docs")
98
+
99
+ # Bulk CSV import/export with COPY INTO
100
+ db.execute("COPY INTO '/tmp/users.csv' FROM mydb.users") # Export
101
+ db.execute("COPY INTO mydb.users FROM '/tmp/users.csv'") # Import
74
102
  ```
75
103
 
76
104
  ### Embedded Mode (no server required)
@@ -40,6 +40,9 @@ with CommitDB('localhost', 3306) as db:
40
40
  # Insert data
41
41
  db.execute("INSERT INTO mydb.users (id, name, email) VALUES (1, 'Alice', 'alice@example.com')")
42
42
  db.execute("INSERT INTO mydb.users (id, name, email) VALUES (2, 'Bob', 'bob@example.com')")
43
+
44
+ # Bulk insert (multiple rows in one statement)
45
+ db.execute("INSERT INTO mydb.users (id, name, email) VALUES (3, 'Charlie', 'c@example.com'), (4, 'Diana', 'd@example.com')")
43
46
 
44
47
  # Query data - returns iterable of dictionaries
45
48
  result = db.query('SELECT * FROM mydb.users')
@@ -48,7 +51,32 @@ with CommitDB('localhost', 3306) as db:
48
51
  print(f" {row['id']}: {row['name']} ({row['email']})")
49
52
 
50
53
  # Use convenience methods
51
- db.insert('mydb', 'users', ['id', 'name', 'email'], [3, 'Charlie', 'charlie@example.com'])
54
+ db.insert('mydb', 'users', ['id', 'name', 'email'], [5, 'Eve', 'eve@example.com'])
55
+
56
+ # Use IN operator for multiple values
57
+ result = db.query("SELECT * FROM mydb.users WHERE id IN (1, 3)")
58
+
59
+ # Modify table schema
60
+ db.execute('ALTER TABLE mydb.users ADD COLUMN phone STRING')
61
+ db.execute('ALTER TABLE mydb.users RENAME COLUMN phone TO mobile')
62
+ db.execute('ALTER TABLE mydb.users DROP COLUMN mobile')
63
+
64
+ # Use string functions
65
+ result = db.query('SELECT UPPER(name) AS upper_name FROM mydb.users')
66
+ result = db.query("SELECT CONCAT(name, '@example.com') AS email FROM mydb.users")
67
+
68
+ # Use date functions
69
+ result = db.query('SELECT NOW() FROM mydb.users')
70
+ result = db.query("SELECT YEAR(created_at), MONTH(created_at) FROM mydb.events")
71
+
72
+ # Use JSON columns and functions
73
+ db.execute("CREATE TABLE mydb.docs (id INT PRIMARY KEY, data JSON)")
74
+ db.execute("INSERT INTO mydb.docs (id, data) VALUES (1, '{\"name\":\"Alice\"}')")
75
+ result = db.query("SELECT JSON_EXTRACT(data, '$.name') FROM mydb.docs")
76
+
77
+ # Bulk CSV import/export with COPY INTO
78
+ db.execute("COPY INTO '/tmp/users.csv' FROM mydb.users") # Export
79
+ db.execute("COPY INTO mydb.users FROM '/tmp/users.csv'") # Import
52
80
  ```
53
81
 
54
82
  ### Embedded Mode (no server required)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: commitdb
3
- Version: 1.6.0
3
+ Version: 2.0.0
4
4
  Summary: Python driver for CommitDB SQL Server
5
5
  Author: CommitDB Contributors
6
6
  License: Apache-2.0
@@ -62,6 +62,9 @@ with CommitDB('localhost', 3306) as db:
62
62
  # Insert data
63
63
  db.execute("INSERT INTO mydb.users (id, name, email) VALUES (1, 'Alice', 'alice@example.com')")
64
64
  db.execute("INSERT INTO mydb.users (id, name, email) VALUES (2, 'Bob', 'bob@example.com')")
65
+
66
+ # Bulk insert (multiple rows in one statement)
67
+ db.execute("INSERT INTO mydb.users (id, name, email) VALUES (3, 'Charlie', 'c@example.com'), (4, 'Diana', 'd@example.com')")
65
68
 
66
69
  # Query data - returns iterable of dictionaries
67
70
  result = db.query('SELECT * FROM mydb.users')
@@ -70,7 +73,32 @@ with CommitDB('localhost', 3306) as db:
70
73
  print(f" {row['id']}: {row['name']} ({row['email']})")
71
74
 
72
75
  # Use convenience methods
73
- db.insert('mydb', 'users', ['id', 'name', 'email'], [3, 'Charlie', 'charlie@example.com'])
76
+ db.insert('mydb', 'users', ['id', 'name', 'email'], [5, 'Eve', 'eve@example.com'])
77
+
78
+ # Use IN operator for multiple values
79
+ result = db.query("SELECT * FROM mydb.users WHERE id IN (1, 3)")
80
+
81
+ # Modify table schema
82
+ db.execute('ALTER TABLE mydb.users ADD COLUMN phone STRING')
83
+ db.execute('ALTER TABLE mydb.users RENAME COLUMN phone TO mobile')
84
+ db.execute('ALTER TABLE mydb.users DROP COLUMN mobile')
85
+
86
+ # Use string functions
87
+ result = db.query('SELECT UPPER(name) AS upper_name FROM mydb.users')
88
+ result = db.query("SELECT CONCAT(name, '@example.com') AS email FROM mydb.users")
89
+
90
+ # Use date functions
91
+ result = db.query('SELECT NOW() FROM mydb.users')
92
+ result = db.query("SELECT YEAR(created_at), MONTH(created_at) FROM mydb.events")
93
+
94
+ # Use JSON columns and functions
95
+ db.execute("CREATE TABLE mydb.docs (id INT PRIMARY KEY, data JSON)")
96
+ db.execute("INSERT INTO mydb.docs (id, data) VALUES (1, '{\"name\":\"Alice\"}')")
97
+ result = db.query("SELECT JSON_EXTRACT(data, '$.name') FROM mydb.docs")
98
+
99
+ # Bulk CSV import/export with COPY INTO
100
+ db.execute("COPY INTO '/tmp/users.csv' FROM mydb.users") # Export
101
+ db.execute("COPY INTO mydb.users FROM '/tmp/users.csv'") # Import
74
102
  ```
75
103
 
76
104
  ### Embedded Mode (no server required)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "commitdb"
7
- version = "1.6.0"
7
+ version = "2.0.0"
8
8
  description = "Python driver for CommitDB SQL Server"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -318,6 +318,149 @@ class TestCommitDBLocal:
318
318
  with pytest.raises(CommitDBError):
319
319
  db.query('SELECT * FROM nonexistent.table')
320
320
 
321
+ def test_in_operator(self, db):
322
+ """Test IN operator for filtering."""
323
+ db.execute('CREATE DATABASE in_test')
324
+ db.execute('CREATE TABLE in_test.items (id INT PRIMARY KEY, status STRING, category STRING)')
325
+
326
+ # Insert test data
327
+ db.execute("INSERT INTO in_test.items (id, status, category) VALUES (1, 'active', 'A')")
328
+ db.execute("INSERT INTO in_test.items (id, status, category) VALUES (2, 'pending', 'B')")
329
+ db.execute("INSERT INTO in_test.items (id, status, category) VALUES (3, 'active', 'C')")
330
+ db.execute("INSERT INTO in_test.items (id, status, category) VALUES (4, 'archived', 'A')")
331
+ db.execute("INSERT INTO in_test.items (id, status, category) VALUES (5, 'pending', 'B')")
332
+
333
+ # Test IN with strings
334
+ result = db.query("SELECT * FROM in_test.items WHERE status IN ('active', 'pending')")
335
+ assert len(result) == 4
336
+
337
+ # Test IN with single value
338
+ result = db.query("SELECT * FROM in_test.items WHERE status IN ('archived')")
339
+ assert len(result) == 1
340
+
341
+ # Test IN with integers
342
+ result = db.query("SELECT * FROM in_test.items WHERE id IN (1, 3, 5)")
343
+ assert len(result) == 3
344
+
345
+ # Test NOT IN
346
+ result = db.query("SELECT * FROM in_test.items WHERE NOT status IN ('archived')")
347
+ assert len(result) == 4
348
+
349
+ def test_alter_table(self, db):
350
+ """Test ALTER TABLE operations."""
351
+ db.execute('CREATE DATABASE alter_test')
352
+ db.execute('CREATE TABLE alter_test.users (id INT PRIMARY KEY, name STRING)')
353
+
354
+ # Test ADD COLUMN
355
+ result = db.execute('ALTER TABLE alter_test.users ADD COLUMN email STRING')
356
+ assert isinstance(result, CommitResult)
357
+
358
+ # Verify column was added
359
+ result = db.query('DESCRIBE alter_test.users')
360
+ assert len(result) == 3
361
+
362
+ # Test MODIFY COLUMN
363
+ result = db.execute('ALTER TABLE alter_test.users MODIFY COLUMN email TEXT')
364
+ assert isinstance(result, CommitResult)
365
+
366
+ # Test RENAME COLUMN
367
+ result = db.execute('ALTER TABLE alter_test.users RENAME COLUMN email TO contact')
368
+ assert isinstance(result, CommitResult)
369
+
370
+ # Verify rename
371
+ result = db.query('DESCRIBE alter_test.users')
372
+ column_names = [row['Column'] for row in result]
373
+ assert 'contact' in column_names
374
+ assert 'email' not in column_names
375
+
376
+ # Test DROP COLUMN
377
+ result = db.execute('ALTER TABLE alter_test.users DROP COLUMN contact')
378
+ assert isinstance(result, CommitResult)
379
+
380
+ # Verify column was dropped
381
+ result = db.query('DESCRIBE alter_test.users')
382
+ assert len(result) == 2
383
+
384
+ def test_string_functions(self, db):
385
+ """Test string functions like UPPER, LOWER, CONCAT, etc."""
386
+ db.execute('CREATE DATABASE strfunc_test')
387
+ db.execute('CREATE TABLE strfunc_test.data (id INT PRIMARY KEY, name STRING)')
388
+
389
+ db.execute("INSERT INTO strfunc_test.data (id, name) VALUES (1, 'Alice')")
390
+ db.execute("INSERT INTO strfunc_test.data (id, name) VALUES (2, 'Bob')")
391
+
392
+ # Test UPPER
393
+ result = db.query('SELECT UPPER(name) FROM strfunc_test.data WHERE id = 1')
394
+ assert len(result) == 1
395
+ assert list(result[0].values())[0] == 'ALICE'
396
+
397
+ # Test LOWER
398
+ result = db.query('SELECT LOWER(name) FROM strfunc_test.data WHERE id = 1')
399
+ assert len(result) == 1
400
+ assert list(result[0].values())[0] == 'alice'
401
+
402
+ # Test LENGTH
403
+ result = db.query('SELECT LENGTH(name) FROM strfunc_test.data WHERE id = 2')
404
+ assert len(result) == 1
405
+ assert list(result[0].values())[0] == '3'
406
+
407
+ # Test CONCAT
408
+ result = db.query("SELECT CONCAT(name, '-test') FROM strfunc_test.data WHERE id = 1")
409
+ assert len(result) == 1
410
+ assert list(result[0].values())[0] == 'Alice-test'
411
+
412
+ def test_date_functions(self, db):
413
+ """Test date functions like NOW, YEAR, MONTH, DAY, etc."""
414
+ db.execute('CREATE DATABASE datefunc_test')
415
+ db.execute('CREATE TABLE datefunc_test.events (id INT PRIMARY KEY, name STRING, created STRING)')
416
+
417
+ db.execute("INSERT INTO datefunc_test.events (id, name, created) VALUES (1, 'Event1', '2024-06-15 14:30:00')")
418
+
419
+ # Test NOW()
420
+ result = db.query('SELECT NOW() FROM datefunc_test.events WHERE id = 1')
421
+ assert len(result) == 1
422
+ assert len(list(result[0].values())[0]) > 0 # Non-empty
423
+
424
+ # Test YEAR
425
+ result = db.query('SELECT YEAR(created) FROM datefunc_test.events WHERE id = 1')
426
+ assert len(result) == 1
427
+ assert list(result[0].values())[0] == '2024'
428
+
429
+ # Test MONTH
430
+ result = db.query('SELECT MONTH(created) FROM datefunc_test.events WHERE id = 1')
431
+ assert len(result) == 1
432
+ assert list(result[0].values())[0] == '6'
433
+
434
+ # Test DAY
435
+ result = db.query('SELECT DAY(created) FROM datefunc_test.events WHERE id = 1')
436
+ assert len(result) == 1
437
+ assert list(result[0].values())[0] == '15'
438
+
439
+ # Test DATE
440
+ result = db.query('SELECT DATE(created) FROM datefunc_test.events WHERE id = 1')
441
+ assert len(result) == 1
442
+ assert list(result[0].values())[0] == '2024-06-15'
443
+
444
+ def test_date_columns(self, db):
445
+ """Test DATE/TIMESTAMP column types and NOW() in INSERT."""
446
+ db.execute('CREATE DATABASE datecol_test')
447
+ db.execute('CREATE TABLE datecol_test.events (id INT PRIMARY KEY, name STRING, event_date DATE, created_at TIMESTAMP)')
448
+
449
+ # Test INSERT with NOW()
450
+ result = db.execute("INSERT INTO datecol_test.events (id, name, event_date, created_at) VALUES (1, 'Event1', '2024-06-15', NOW())")
451
+ assert isinstance(result, CommitResult)
452
+
453
+ # Verify the data was inserted
454
+ result = db.query('SELECT created_at FROM datecol_test.events WHERE id = 1')
455
+ assert len(result) == 1
456
+ assert len(list(result[0].values())[0]) > 0 # Non-empty timestamp
457
+
458
+ # Test NOW() for DATE column
459
+ db.execute("INSERT INTO datecol_test.events (id, name, event_date, created_at) VALUES (2, 'Event2', NOW(), '2024-12-25 08:00:00')")
460
+ result = db.query('SELECT event_date FROM datecol_test.events WHERE id = 2')
461
+ assert len(result) == 1
462
+ assert len(list(result[0].values())[0]) == 10 # Date format YYYY-MM-DD
463
+
321
464
  def test_create_branch(self, db):
322
465
  """Test CREATE BRANCH SQL syntax."""
323
466
  db.execute('CREATE DATABASE branch_test1')
@@ -355,6 +498,59 @@ class TestCommitDBLocal:
355
498
  db.execute('CHECKOUT master')
356
499
  result = db.query('SELECT * FROM branch_test2.data')
357
500
  assert len(result) == 1
501
+
502
+ def test_bulk_insert(self, db):
503
+ """Test bulk INSERT with multiple value rows."""
504
+ db.execute('CREATE DATABASE bulk_test')
505
+ db.execute('CREATE TABLE bulk_test.items (id INT PRIMARY KEY, name STRING, value INT)')
506
+
507
+ # Bulk insert multiple rows
508
+ result = db.execute("INSERT INTO bulk_test.items (id, name, value) VALUES (1, 'Item1', 100), (2, 'Item2', 200), (3, 'Item3', 300)")
509
+ assert result.records_written == 3
510
+
511
+ # Verify all rows were inserted
512
+ result = db.query('SELECT * FROM bulk_test.items ORDER BY id ASC')
513
+ assert len(result) == 3
514
+ assert result[0]['name'] == 'Item1'
515
+ assert result[1]['name'] == 'Item2'
516
+ assert result[2]['name'] == 'Item3'
517
+
518
+ def test_copy_into(self, db):
519
+ """Test COPY INTO for bulk CSV import/export."""
520
+ import tempfile
521
+ import os
522
+
523
+ db.execute('CREATE DATABASE copy_test')
524
+ db.execute('CREATE TABLE copy_test.users (id INT PRIMARY KEY, name STRING, email STRING)')
525
+
526
+ # Insert data
527
+ db.execute("INSERT INTO copy_test.users (id, name, email) VALUES (1, 'Alice', 'alice@test.com')")
528
+ db.execute("INSERT INTO copy_test.users (id, name, email) VALUES (2, 'Bob', 'bob@test.com')")
529
+
530
+ # Export to CSV
531
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.csv', delete=False) as f:
532
+ export_path = f.name
533
+
534
+ try:
535
+ result = db.execute(f"COPY INTO '{export_path}' FROM copy_test.users")
536
+ assert result.records_written == 2
537
+
538
+ # Verify file exists and has content
539
+ with open(export_path, 'r') as f:
540
+ content = f.read()
541
+ assert 'Alice' in content
542
+ assert 'id,name,email' in content
543
+
544
+ # Create new table and import
545
+ db.execute('CREATE TABLE copy_test.imported (id INT PRIMARY KEY, name STRING, email STRING)')
546
+ result = db.execute(f"COPY INTO copy_test.imported FROM '{export_path}'")
547
+ assert result.records_written == 2
548
+
549
+ # Verify imported data
550
+ result = db.query('SELECT * FROM copy_test.imported')
551
+ assert len(result) == 2
552
+ finally:
553
+ os.unlink(export_path)
358
554
 
359
555
  def test_merge(self, db):
360
556
  """Test MERGE SQL syntax."""
File without changes
File without changes
File without changes
File without changes
File without changes