2013-07-14 22:51:35 +02:00
|
|
|
import os
|
2013-04-01 19:38:02 +02:00
|
|
|
import unittest
|
|
|
|
|
from datetime import datetime
|
2020-06-28 23:06:59 +02:00
|
|
|
from collections import OrderedDict
|
2020-08-23 12:23:00 +02:00
|
|
|
from sqlalchemy import TEXT, BIGINT
|
2017-05-16 16:57:07 +02:00
|
|
|
from sqlalchemy.exc import IntegrityError, SQLAlchemyError, ArgumentError
|
2013-12-18 04:21:10 +01:00
|
|
|
|
2020-03-13 14:29:03 +01:00
|
|
|
from dataset import connect, chunked
|
2013-12-18 04:21:10 +01:00
|
|
|
|
2015-06-08 10:54:46 +02:00
|
|
|
from .sample_data import TEST_DATA, TEST_CITY_1
|
2013-04-01 19:38:02 +02:00
|
|
|
|
2013-04-05 11:46:45 +02:00
|
|
|
|
2013-04-01 19:38:02 +02:00
|
|
|
class DatabaseTestCase(unittest.TestCase):
|
|
|
|
|
def setUp(self):
|
2020-06-28 23:06:59 +02:00
|
|
|
self.db = connect()
|
2020-08-02 12:52:11 +02:00
|
|
|
self.tbl = self.db["weather"]
|
2017-09-02 17:17:24 +02:00
|
|
|
self.tbl.insert_many(TEST_DATA)
|
2013-04-01 19:38:02 +02:00
|
|
|
|
2014-01-31 18:56:58 +01:00
|
|
|
def tearDown(self):
|
|
|
|
|
for table in self.db.tables:
|
|
|
|
|
self.db[table].drop()
|
|
|
|
|
|
2013-07-14 22:51:35 +02:00
|
|
|
def test_valid_database_url(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
assert self.db.url, os.environ["DATABASE_URL"]
|
2013-07-14 22:51:35 +02:00
|
|
|
|
2013-11-15 22:23:03 +01:00
|
|
|
def test_database_url_query_string(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
db = connect("sqlite:///:memory:/?cached_statements=1")
|
|
|
|
|
assert "cached_statements" in db.url, db.url
|
2013-11-15 22:23:03 +01:00
|
|
|
|
2013-04-01 22:09:16 +02:00
|
|
|
def test_tables(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
assert self.db.tables == ["weather"], self.db.tables
|
2013-04-01 22:09:16 +02:00
|
|
|
|
2014-08-29 20:12:25 +02:00
|
|
|
def test_contains(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
assert "weather" in self.db, self.db.tables
|
2014-08-29 20:12:25 +02:00
|
|
|
|
2013-04-01 19:38:02 +02:00
|
|
|
def test_create_table(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
table = self.db["foo"]
|
2021-10-30 12:06:58 +02:00
|
|
|
assert self.db.has_table(table.table.name)
|
2013-04-01 19:38:02 +02:00
|
|
|
assert len(table.table.columns) == 1, table.table.columns
|
2020-08-02 12:52:11 +02:00
|
|
|
assert "id" in table.table.c, table.table.c
|
2013-04-01 19:46:17 +02:00
|
|
|
|
2017-09-02 17:25:52 +02:00
|
|
|
def test_create_table_no_ids(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
if "mysql" in self.db.engine.dialect.dbapi.__name__:
|
2017-09-02 17:31:05 +02:00
|
|
|
return
|
2020-08-02 12:52:11 +02:00
|
|
|
if "sqlite" in self.db.engine.dialect.dbapi.__name__:
|
2017-09-02 17:31:05 +02:00
|
|
|
return
|
2017-09-02 17:25:52 +02:00
|
|
|
table = self.db.create_table("foo_no_id", primary_id=False)
|
|
|
|
|
assert table.table.exists()
|
|
|
|
|
assert len(table.table.columns) == 0, table.table.columns
|
|
|
|
|
|
2013-09-08 17:35:43 +02:00
|
|
|
def test_create_table_custom_id1(self):
|
|
|
|
|
pid = "string_id"
|
2017-09-02 17:31:05 +02:00
|
|
|
table = self.db.create_table("foo2", pid, self.db.types.string(255))
|
2021-10-30 12:06:58 +02:00
|
|
|
assert self.db.has_table(table.table.name)
|
2013-09-08 17:35:43 +02:00
|
|
|
assert len(table.table.columns) == 1, table.table.columns
|
|
|
|
|
assert pid in table.table.c, table.table.c
|
2020-08-02 12:52:11 +02:00
|
|
|
table.insert({pid: "foobar"})
|
|
|
|
|
assert table.find_one(string_id="foobar")[pid] == "foobar"
|
2013-09-08 17:35:43 +02:00
|
|
|
|
|
|
|
|
def test_create_table_custom_id2(self):
|
2013-12-07 06:22:29 +01:00
|
|
|
pid = "string_id"
|
2017-09-02 16:47:04 +02:00
|
|
|
table = self.db.create_table("foo3", pid, self.db.types.string(50))
|
2021-10-30 12:06:58 +02:00
|
|
|
assert self.db.has_table(table.table.name)
|
2013-12-07 06:22:29 +01:00
|
|
|
assert len(table.table.columns) == 1, table.table.columns
|
|
|
|
|
assert pid in table.table.c, table.table.c
|
|
|
|
|
|
2020-08-02 12:52:11 +02:00
|
|
|
table.insert({pid: "foobar"})
|
|
|
|
|
assert table.find_one(string_id="foobar")[pid] == "foobar"
|
2013-12-07 06:22:29 +01:00
|
|
|
|
|
|
|
|
def test_create_table_custom_id3(self):
|
2013-09-08 17:35:43 +02:00
|
|
|
pid = "int_id"
|
2014-01-25 21:45:30 +01:00
|
|
|
table = self.db.create_table("foo4", primary_id=pid)
|
2021-10-30 12:06:58 +02:00
|
|
|
assert self.db.has_table(table.table.name)
|
2013-09-08 17:35:43 +02:00
|
|
|
assert len(table.table.columns) == 1, table.table.columns
|
|
|
|
|
assert pid in table.table.c, table.table.c
|
|
|
|
|
|
2017-09-02 16:47:04 +02:00
|
|
|
table.insert({pid: 123})
|
|
|
|
|
table.insert({pid: 124})
|
|
|
|
|
assert table.find_one(int_id=123)[pid] == 123
|
|
|
|
|
assert table.find_one(int_id=124)[pid] == 124
|
|
|
|
|
self.assertRaises(IntegrityError, lambda: table.insert({pid: 123}))
|
2013-09-08 17:35:43 +02:00
|
|
|
|
2013-09-15 20:12:30 +02:00
|
|
|
def test_create_table_shorthand1(self):
|
|
|
|
|
pid = "int_id"
|
2020-08-02 12:52:11 +02:00
|
|
|
table = self.db.get_table("foo5", pid)
|
2013-09-15 20:12:30 +02:00
|
|
|
assert table.table.exists
|
|
|
|
|
assert len(table.table.columns) == 1, table.table.columns
|
|
|
|
|
assert pid in table.table.c, table.table.c
|
|
|
|
|
|
2020-08-02 12:52:11 +02:00
|
|
|
table.insert({"int_id": 123})
|
|
|
|
|
table.insert({"int_id": 124})
|
|
|
|
|
assert table.find_one(int_id=123)["int_id"] == 123
|
|
|
|
|
assert table.find_one(int_id=124)["int_id"] == 124
|
|
|
|
|
self.assertRaises(IntegrityError, lambda: table.insert({"int_id": 123}))
|
2013-09-15 20:12:30 +02:00
|
|
|
|
|
|
|
|
def test_create_table_shorthand2(self):
|
|
|
|
|
pid = "string_id"
|
2020-08-02 12:52:11 +02:00
|
|
|
table = self.db.get_table(
|
|
|
|
|
"foo6", primary_id=pid, primary_type=self.db.types.string(255)
|
|
|
|
|
)
|
2013-09-15 20:12:30 +02:00
|
|
|
assert table.table.exists
|
|
|
|
|
assert len(table.table.columns) == 1, table.table.columns
|
|
|
|
|
assert pid in table.table.c, table.table.c
|
|
|
|
|
|
2020-08-02 12:52:11 +02:00
|
|
|
table.insert({"string_id": "foobar"})
|
|
|
|
|
assert table.find_one(string_id="foobar")["string_id"] == "foobar"
|
2013-09-15 20:12:30 +02:00
|
|
|
|
2014-06-08 23:36:42 +02:00
|
|
|
def test_with(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
init_length = len(self.db["weather"])
|
2015-05-23 14:35:28 +02:00
|
|
|
with self.assertRaises(ValueError):
|
2014-06-11 13:14:42 +02:00
|
|
|
with self.db as tx:
|
2020-08-02 12:52:11 +02:00
|
|
|
tx["weather"].insert(
|
|
|
|
|
{
|
|
|
|
|
"date": datetime(2011, 1, 1),
|
|
|
|
|
"temperature": 1,
|
|
|
|
|
"place": "tmp_place",
|
|
|
|
|
}
|
|
|
|
|
)
|
2015-05-23 14:35:28 +02:00
|
|
|
raise ValueError()
|
2020-08-02 12:52:11 +02:00
|
|
|
assert len(self.db["weather"]) == init_length
|
2014-06-08 23:36:42 +02:00
|
|
|
|
2015-05-23 14:35:28 +02:00
|
|
|
def test_invalid_values(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
if "mysql" in self.db.engine.dialect.dbapi.__name__:
|
2020-06-28 23:06:59 +02:00
|
|
|
# WARNING: mysql seems to be doing some weird type casting
|
|
|
|
|
# upon insert. The mysql-python driver is not affected but
|
|
|
|
|
# it isn't compatible with Python 3
|
2015-05-23 14:35:28 +02:00
|
|
|
# Conclusion: use postgresql.
|
|
|
|
|
return
|
|
|
|
|
with self.assertRaises(SQLAlchemyError):
|
2020-08-02 12:52:11 +02:00
|
|
|
tbl = self.db["weather"]
|
|
|
|
|
tbl.insert(
|
|
|
|
|
{"date": True, "temperature": "wrong_value", "place": "tmp_place"}
|
|
|
|
|
)
|
2015-05-23 14:35:28 +02:00
|
|
|
|
2013-04-01 19:46:17 +02:00
|
|
|
def test_load_table(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
tbl = self.db.load_table("weather")
|
2017-09-02 19:35:01 +02:00
|
|
|
assert tbl.table.name == self.tbl.table.name
|
2013-04-01 19:46:17 +02:00
|
|
|
|
|
|
|
|
def test_query(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
r = self.db.query("SELECT COUNT(*) AS num FROM weather").next()
|
|
|
|
|
assert r["num"] == len(TEST_DATA), r
|
2013-04-01 19:46:17 +02:00
|
|
|
|
2014-01-27 08:58:45 +01:00
|
|
|
def test_table_cache_updates(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
tbl1 = self.db.get_table("people")
|
|
|
|
|
data = OrderedDict([("first_name", "John"), ("last_name", "Smith")])
|
2014-02-18 12:59:12 +01:00
|
|
|
tbl1.insert(data)
|
2020-08-02 12:52:11 +02:00
|
|
|
data["id"] = 1
|
|
|
|
|
tbl2 = self.db.get_table("people")
|
2014-02-18 12:59:12 +01:00
|
|
|
assert dict(tbl2.all().next()) == dict(data), (tbl2.all().next(), data)
|
2014-01-27 08:58:45 +01:00
|
|
|
|
2013-04-01 19:38:02 +02:00
|
|
|
|
2013-04-01 19:56:14 +02:00
|
|
|
class TableTestCase(unittest.TestCase):
|
|
|
|
|
def setUp(self):
|
2020-06-28 23:06:59 +02:00
|
|
|
self.db = connect()
|
2020-08-02 12:52:11 +02:00
|
|
|
self.tbl = self.db["weather"]
|
2013-04-01 19:56:14 +02:00
|
|
|
for row in TEST_DATA:
|
|
|
|
|
self.tbl.insert(row)
|
|
|
|
|
|
2020-08-23 12:23:00 +02:00
|
|
|
def tearDown(self):
|
|
|
|
|
self.tbl.drop()
|
|
|
|
|
|
2013-04-01 19:56:14 +02:00
|
|
|
def test_insert(self):
|
2013-04-05 11:46:45 +02:00
|
|
|
assert len(self.tbl) == len(TEST_DATA), len(self.tbl)
|
2020-08-02 12:52:11 +02:00
|
|
|
last_id = self.tbl.insert(
|
|
|
|
|
{"date": datetime(2011, 1, 2), "temperature": -10, "place": "Berlin"}
|
2013-04-05 11:46:45 +02:00
|
|
|
)
|
2014-01-25 21:45:30 +01:00
|
|
|
assert len(self.tbl) == len(TEST_DATA) + 1, len(self.tbl)
|
2020-08-02 12:52:11 +02:00
|
|
|
assert self.tbl.find_one(id=last_id)["place"] == "Berlin"
|
2013-04-01 19:56:14 +02:00
|
|
|
|
2016-04-22 17:35:14 +02:00
|
|
|
def test_insert_ignore(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
self.tbl.insert_ignore(
|
|
|
|
|
{"date": datetime(2011, 1, 2), "temperature": -10, "place": "Berlin"},
|
|
|
|
|
["place"],
|
2016-04-22 17:35:14 +02:00
|
|
|
)
|
|
|
|
|
assert len(self.tbl) == len(TEST_DATA) + 1, len(self.tbl)
|
2020-08-02 12:52:11 +02:00
|
|
|
self.tbl.insert_ignore(
|
|
|
|
|
{"date": datetime(2011, 1, 2), "temperature": -10, "place": "Berlin"},
|
|
|
|
|
["place"],
|
2016-04-22 17:35:14 +02:00
|
|
|
)
|
|
|
|
|
assert len(self.tbl) == len(TEST_DATA) + 1, len(self.tbl)
|
|
|
|
|
|
|
|
|
|
def test_insert_ignore_all_key(self):
|
2017-09-03 10:05:17 +02:00
|
|
|
for i in range(0, 4):
|
2020-08-02 12:52:11 +02:00
|
|
|
self.tbl.insert_ignore(
|
|
|
|
|
{"date": datetime(2011, 1, 2), "temperature": -10, "place": "Berlin"},
|
|
|
|
|
["date", "temperature", "place"],
|
2016-04-22 17:35:14 +02:00
|
|
|
)
|
2017-09-03 10:05:17 +02:00
|
|
|
assert len(self.tbl) == len(TEST_DATA) + 1, len(self.tbl)
|
2016-04-22 17:35:14 +02:00
|
|
|
|
2020-03-26 03:35:36 +01:00
|
|
|
def test_insert_json(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
last_id = self.tbl.insert(
|
|
|
|
|
{
|
|
|
|
|
"date": datetime(2011, 1, 2),
|
|
|
|
|
"temperature": -10,
|
|
|
|
|
"place": "Berlin",
|
|
|
|
|
"info": {
|
|
|
|
|
"currency": "EUR",
|
|
|
|
|
"language": "German",
|
|
|
|
|
"population": 3292365,
|
|
|
|
|
},
|
2020-03-26 03:35:36 +01:00
|
|
|
}
|
2020-08-02 12:52:11 +02:00
|
|
|
)
|
2020-03-26 03:35:36 +01:00
|
|
|
assert len(self.tbl) == len(TEST_DATA) + 1, len(self.tbl)
|
2020-08-02 12:52:11 +02:00
|
|
|
assert self.tbl.find_one(id=last_id)["place"] == "Berlin"
|
2020-03-26 03:35:36 +01:00
|
|
|
|
2013-04-01 22:03:01 +02:00
|
|
|
def test_upsert(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
self.tbl.upsert(
|
|
|
|
|
{"date": datetime(2011, 1, 2), "temperature": -10, "place": "Berlin"},
|
|
|
|
|
["place"],
|
2013-04-05 11:46:45 +02:00
|
|
|
)
|
2014-01-25 21:45:30 +01:00
|
|
|
assert len(self.tbl) == len(TEST_DATA) + 1, len(self.tbl)
|
2020-08-02 12:52:11 +02:00
|
|
|
self.tbl.upsert(
|
|
|
|
|
{"date": datetime(2011, 1, 2), "temperature": -10, "place": "Berlin"},
|
|
|
|
|
["place"],
|
2013-04-05 11:46:45 +02:00
|
|
|
)
|
2014-01-25 21:45:30 +01:00
|
|
|
assert len(self.tbl) == len(TEST_DATA) + 1, len(self.tbl)
|
2013-04-01 22:03:01 +02:00
|
|
|
|
2017-09-03 10:05:17 +02:00
|
|
|
def test_upsert_single_column(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
table = self.db["banana_single_col"]
|
|
|
|
|
table.upsert({"color": "Yellow"}, ["color"])
|
2017-09-03 10:05:17 +02:00
|
|
|
assert len(table) == 1, len(table)
|
2020-08-02 12:52:11 +02:00
|
|
|
table.upsert({"color": "Yellow"}, ["color"])
|
2017-09-03 10:05:17 +02:00
|
|
|
assert len(table) == 1, len(table)
|
|
|
|
|
|
2013-06-27 14:13:28 +02:00
|
|
|
def test_upsert_all_key(self):
|
2017-09-03 10:05:17 +02:00
|
|
|
assert len(self.tbl) == len(TEST_DATA), len(self.tbl)
|
2014-01-25 21:45:30 +01:00
|
|
|
for i in range(0, 2):
|
2020-08-02 12:52:11 +02:00
|
|
|
self.tbl.upsert(
|
|
|
|
|
{"date": datetime(2011, 1, 2), "temperature": -10, "place": "Berlin"},
|
|
|
|
|
["date", "temperature", "place"],
|
2013-06-27 14:13:28 +02:00
|
|
|
)
|
2017-09-03 10:05:17 +02:00
|
|
|
assert len(self.tbl) == len(TEST_DATA) + 1, len(self.tbl)
|
2013-06-27 14:13:28 +02:00
|
|
|
|
2019-02-15 04:35:47 +01:00
|
|
|
def test_upsert_id(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
table = self.db["banana_with_id"]
|
|
|
|
|
data = dict(id=10, title="I am a banana!")
|
|
|
|
|
table.upsert(data, ["id"])
|
2019-02-15 04:35:47 +01:00
|
|
|
assert len(table) == 1, len(table)
|
|
|
|
|
|
2015-05-21 17:17:14 +02:00
|
|
|
def test_update_while_iter(self):
|
|
|
|
|
for row in self.tbl:
|
2020-08-02 12:52:11 +02:00
|
|
|
row["foo"] = "bar"
|
|
|
|
|
self.tbl.update(row, ["place", "date"])
|
2017-09-03 10:05:17 +02:00
|
|
|
assert len(self.tbl) == len(TEST_DATA), len(self.tbl)
|
2015-05-21 17:17:14 +02:00
|
|
|
|
2015-05-21 23:21:47 +02:00
|
|
|
def test_weird_column_names(self):
|
|
|
|
|
with self.assertRaises(ValueError):
|
2020-08-02 12:52:11 +02:00
|
|
|
self.tbl.insert(
|
|
|
|
|
{
|
|
|
|
|
"date": datetime(2011, 1, 2),
|
|
|
|
|
"temperature": -10,
|
|
|
|
|
"foo.bar": "Berlin",
|
|
|
|
|
"qux.bar": "Huhu",
|
|
|
|
|
}
|
|
|
|
|
)
|
2015-05-21 23:21:47 +02:00
|
|
|
|
2020-02-23 19:13:34 +01:00
|
|
|
def test_cased_column_names(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
tbl = self.db["cased_column_names"]
|
2020-08-23 12:10:10 +02:00
|
|
|
tbl.insert({"place": "Berlin"})
|
|
|
|
|
tbl.insert({"Place": "Berlin"})
|
|
|
|
|
tbl.insert({"PLACE ": "Berlin"})
|
2020-02-23 19:13:34 +01:00
|
|
|
assert len(tbl.columns) == 2, tbl.columns
|
2020-08-02 12:52:11 +02:00
|
|
|
assert len(list(tbl.find(Place="Berlin"))) == 3
|
|
|
|
|
assert len(list(tbl.find(place="Berlin"))) == 3
|
|
|
|
|
assert len(list(tbl.find(PLACE="Berlin"))) == 3
|
2020-02-23 19:13:34 +01:00
|
|
|
|
2015-05-23 15:30:19 +02:00
|
|
|
def test_invalid_column_names(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
tbl = self.db["weather"]
|
2015-05-23 15:30:19 +02:00
|
|
|
with self.assertRaises(ValueError):
|
2020-08-02 12:52:11 +02:00
|
|
|
tbl.insert({None: "banana"})
|
2015-05-23 15:30:19 +02:00
|
|
|
|
|
|
|
|
with self.assertRaises(ValueError):
|
2020-08-02 12:52:11 +02:00
|
|
|
tbl.insert({"": "banana"})
|
2015-05-23 15:30:19 +02:00
|
|
|
|
|
|
|
|
with self.assertRaises(ValueError):
|
2020-08-02 12:52:11 +02:00
|
|
|
tbl.insert({"-": "banana"})
|
2015-05-23 15:30:19 +02:00
|
|
|
|
2013-04-01 22:03:01 +02:00
|
|
|
def test_delete(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
self.tbl.insert(
|
|
|
|
|
{"date": datetime(2011, 1, 2), "temperature": -10, "place": "Berlin"}
|
2013-04-05 11:46:45 +02:00
|
|
|
)
|
2017-05-16 16:57:07 +02:00
|
|
|
original_count = len(self.tbl)
|
2014-01-25 21:45:30 +01:00
|
|
|
assert len(self.tbl) == len(TEST_DATA) + 1, len(self.tbl)
|
2017-05-16 16:57:07 +02:00
|
|
|
# Test bad use of API
|
|
|
|
|
with self.assertRaises(ArgumentError):
|
2020-08-02 12:52:11 +02:00
|
|
|
self.tbl.delete({"place": "Berlin"})
|
2017-05-16 16:57:07 +02:00
|
|
|
assert len(self.tbl) == original_count, len(self.tbl)
|
|
|
|
|
|
2020-08-02 12:52:11 +02:00
|
|
|
assert self.tbl.delete(place="Berlin") is True, "should return 1"
|
2013-04-05 11:46:45 +02:00
|
|
|
assert len(self.tbl) == len(TEST_DATA), len(self.tbl)
|
2020-08-02 12:52:11 +02:00
|
|
|
assert self.tbl.delete() is True, "should return non zero"
|
2013-04-05 11:53:50 +02:00
|
|
|
assert len(self.tbl) == 0, len(self.tbl)
|
2013-04-01 22:03:01 +02:00
|
|
|
|
2014-02-03 22:52:00 +01:00
|
|
|
def test_repr(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
assert (
|
|
|
|
|
repr(self.tbl) == "<Table(weather)>"
|
|
|
|
|
), "the representation should be <Table(weather)>"
|
2014-02-03 22:52:00 +01:00
|
|
|
|
2014-01-31 23:27:40 +01:00
|
|
|
def test_delete_nonexist_entry(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
assert (
|
|
|
|
|
self.tbl.delete(place="Berlin") is False
|
|
|
|
|
), "entry not exist, should fail to delete"
|
2014-01-31 23:27:40 +01:00
|
|
|
|
2013-04-01 22:03:01 +02:00
|
|
|
def test_find_one(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
self.tbl.insert(
|
|
|
|
|
{"date": datetime(2011, 1, 2), "temperature": -10, "place": "Berlin"}
|
|
|
|
|
)
|
|
|
|
|
d = self.tbl.find_one(place="Berlin")
|
|
|
|
|
assert d["temperature"] == -10, d
|
|
|
|
|
d = self.tbl.find_one(place="Atlantis")
|
2013-04-01 22:03:01 +02:00
|
|
|
assert d is None, d
|
|
|
|
|
|
2015-05-21 18:05:26 +02:00
|
|
|
def test_count(self):
|
|
|
|
|
assert len(self.tbl) == 6, len(self.tbl)
|
2017-12-05 17:21:08 +01:00
|
|
|
length = self.tbl.count(place=TEST_CITY_1)
|
|
|
|
|
assert length == 3, length
|
2015-05-21 18:05:26 +02:00
|
|
|
|
2013-04-01 22:03:01 +02:00
|
|
|
def test_find(self):
|
2013-12-18 11:33:45 +01:00
|
|
|
ds = list(self.tbl.find(place=TEST_CITY_1))
|
2013-04-05 11:46:45 +02:00
|
|
|
assert len(ds) == 3, ds
|
2013-12-18 11:33:45 +01:00
|
|
|
ds = list(self.tbl.find(place=TEST_CITY_1, _limit=2))
|
2013-04-05 11:46:45 +02:00
|
|
|
assert len(ds) == 2, ds
|
2014-01-25 21:20:18 +01:00
|
|
|
ds = list(self.tbl.find(place=TEST_CITY_1, _limit=2, _step=1))
|
|
|
|
|
assert len(ds) == 2, ds
|
|
|
|
|
ds = list(self.tbl.find(place=TEST_CITY_1, _limit=1, _step=2))
|
|
|
|
|
assert len(ds) == 1, ds
|
2016-10-15 22:55:50 +02:00
|
|
|
ds = list(self.tbl.find(_step=2))
|
|
|
|
|
assert len(ds) == len(TEST_DATA), ds
|
2020-08-02 12:52:11 +02:00
|
|
|
ds = list(self.tbl.find(order_by=["temperature"]))
|
|
|
|
|
assert ds[0]["temperature"] == -1, ds
|
|
|
|
|
ds = list(self.tbl.find(order_by=["-temperature"]))
|
|
|
|
|
assert ds[0]["temperature"] == 8, ds
|
2016-03-24 06:24:12 +01:00
|
|
|
ds = list(self.tbl.find(self.tbl.table.columns.temperature > 4))
|
|
|
|
|
assert len(ds) == 3, ds
|
2014-01-31 21:52:57 +01:00
|
|
|
|
2018-06-13 02:29:32 +02:00
|
|
|
def test_find_dsl(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
ds = list(self.tbl.find(place={"like": "%lw%"}))
|
2018-06-13 02:29:32 +02:00
|
|
|
assert len(ds) == 3, ds
|
2020-08-02 12:52:11 +02:00
|
|
|
ds = list(self.tbl.find(temperature={">": 5}))
|
2018-06-13 02:29:32 +02:00
|
|
|
assert len(ds) == 2, ds
|
2020-08-02 12:52:11 +02:00
|
|
|
ds = list(self.tbl.find(temperature={">=": 5}))
|
2018-06-13 02:29:32 +02:00
|
|
|
assert len(ds) == 3, ds
|
2020-08-02 12:52:11 +02:00
|
|
|
ds = list(self.tbl.find(temperature={"<": 0}))
|
2018-06-13 02:29:32 +02:00
|
|
|
assert len(ds) == 1, ds
|
2020-08-02 12:52:11 +02:00
|
|
|
ds = list(self.tbl.find(temperature={"<=": 0}))
|
2018-06-13 02:29:32 +02:00
|
|
|
assert len(ds) == 2, ds
|
2020-08-02 12:52:11 +02:00
|
|
|
ds = list(self.tbl.find(temperature={"!=": -1}))
|
2018-06-13 02:29:32 +02:00
|
|
|
assert len(ds) == 5, ds
|
2020-08-02 12:52:11 +02:00
|
|
|
ds = list(self.tbl.find(temperature={"between": [5, 8]}))
|
2018-06-13 02:29:32 +02:00
|
|
|
assert len(ds) == 3, ds
|
2020-08-02 12:52:11 +02:00
|
|
|
ds = list(self.tbl.find(place={"=": "G€lway"}))
|
2019-08-08 13:55:29 +02:00
|
|
|
assert len(ds) == 3, ds
|
2020-08-02 12:52:11 +02:00
|
|
|
ds = list(self.tbl.find(place={"ilike": "%LwAy"}))
|
2019-08-08 13:55:29 +02:00
|
|
|
assert len(ds) == 3, ds
|
2018-06-13 02:29:32 +02:00
|
|
|
|
2014-01-31 21:52:57 +01:00
|
|
|
def test_offset(self):
|
|
|
|
|
ds = list(self.tbl.find(place=TEST_CITY_1, _offset=1))
|
|
|
|
|
assert len(ds) == 2, ds
|
|
|
|
|
ds = list(self.tbl.find(place=TEST_CITY_1, _limit=2, _offset=2))
|
|
|
|
|
assert len(ds) == 1, ds
|
2013-04-01 22:03:01 +02:00
|
|
|
|
2017-12-04 23:22:08 +01:00
|
|
|
def test_streamed(self):
|
|
|
|
|
ds = list(self.tbl.find(place=TEST_CITY_1, _streamed=True, _step=1))
|
|
|
|
|
assert len(ds) == 3, len(ds)
|
|
|
|
|
for row in self.tbl.find(place=TEST_CITY_1, _streamed=True, _step=1):
|
2020-08-02 12:52:11 +02:00
|
|
|
row["temperature"] = -1
|
|
|
|
|
self.tbl.update(row, ["id"])
|
2017-12-04 23:22:08 +01:00
|
|
|
|
2013-04-01 19:56:14 +02:00
|
|
|
def test_distinct(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
x = list(self.tbl.distinct("place"))
|
2013-04-05 11:46:45 +02:00
|
|
|
assert len(x) == 2, x
|
2020-08-02 12:52:11 +02:00
|
|
|
x = list(self.tbl.distinct("place", "date"))
|
2013-04-05 11:46:45 +02:00
|
|
|
assert len(x) == 6, x
|
2020-08-02 12:52:11 +02:00
|
|
|
x = list(
|
|
|
|
|
self.tbl.distinct(
|
|
|
|
|
"place",
|
|
|
|
|
"date",
|
|
|
|
|
self.tbl.table.columns.date >= datetime(2011, 1, 2, 0, 0),
|
|
|
|
|
)
|
|
|
|
|
)
|
2016-03-24 06:24:12 +01:00
|
|
|
assert len(x) == 4, x
|
2013-04-01 19:56:14 +02:00
|
|
|
|
2020-08-02 12:52:11 +02:00
|
|
|
x = list(self.tbl.distinct("temperature", place="B€rkeley"))
|
2018-09-26 17:36:09 +02:00
|
|
|
assert len(x) == 3, x
|
2020-08-02 12:52:11 +02:00
|
|
|
x = list(self.tbl.distinct("temperature", place=["B€rkeley", "G€lway"]))
|
2018-09-26 17:36:09 +02:00
|
|
|
assert len(x) == 6, x
|
|
|
|
|
|
2013-04-04 15:43:05 +02:00
|
|
|
def test_insert_many(self):
|
2013-12-18 11:50:34 +01:00
|
|
|
data = TEST_DATA * 100
|
|
|
|
|
self.tbl.insert_many(data, chunk_size=13)
|
2020-08-23 12:23:00 +02:00
|
|
|
assert len(self.tbl) == len(data) + 6, (len(self.tbl), len(data))
|
2013-04-04 15:43:05 +02:00
|
|
|
|
2020-03-13 14:29:03 +01:00
|
|
|
def test_chunked_insert(self):
|
|
|
|
|
data = TEST_DATA * 100
|
2020-03-13 15:05:07 +01:00
|
|
|
with chunked.ChunkedInsert(self.tbl) as chunk_tbl:
|
2020-03-13 14:29:03 +01:00
|
|
|
for item in data:
|
|
|
|
|
chunk_tbl.insert(item)
|
2020-08-23 12:10:10 +02:00
|
|
|
assert len(self.tbl) == len(data) + 6, (len(self.tbl), len(data))
|
2020-03-13 14:29:03 +01:00
|
|
|
|
|
|
|
|
def test_chunked_insert_callback(self):
|
|
|
|
|
data = TEST_DATA * 100
|
|
|
|
|
N = 0
|
2020-03-13 15:05:07 +01:00
|
|
|
|
2020-03-13 14:29:03 +01:00
|
|
|
def callback(queue):
|
|
|
|
|
nonlocal N
|
|
|
|
|
N += len(queue)
|
2020-08-02 12:52:11 +02:00
|
|
|
|
2020-03-13 15:05:07 +01:00
|
|
|
with chunked.ChunkedInsert(self.tbl, callback=callback) as chunk_tbl:
|
2020-03-13 14:29:03 +01:00
|
|
|
for item in data:
|
|
|
|
|
chunk_tbl.insert(item)
|
|
|
|
|
assert len(data) == N
|
|
|
|
|
assert len(self.tbl) == len(data) + 6
|
|
|
|
|
|
2019-07-08 19:10:00 +02:00
|
|
|
def test_update_many(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
tbl = self.db["update_many_test"]
|
|
|
|
|
tbl.insert_many([dict(temp=10), dict(temp=20), dict(temp=30)])
|
|
|
|
|
tbl.update_many([dict(id=1, temp=50), dict(id=3, temp=50)], "id")
|
2019-07-08 19:10:00 +02:00
|
|
|
|
|
|
|
|
# Ensure data has been updated.
|
2020-08-02 12:52:11 +02:00
|
|
|
assert tbl.find_one(id=1)["temp"] == tbl.find_one(id=3)["temp"]
|
2019-07-08 19:10:00 +02:00
|
|
|
|
2020-03-13 19:00:54 +01:00
|
|
|
def test_chunked_update(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
tbl = self.db["update_many_test"]
|
|
|
|
|
tbl.insert_many(
|
|
|
|
|
[
|
|
|
|
|
dict(temp=10, location="asdf"),
|
|
|
|
|
dict(temp=20, location="qwer"),
|
|
|
|
|
dict(temp=30, location="asdf"),
|
|
|
|
|
]
|
|
|
|
|
)
|
2020-03-13 19:00:54 +01:00
|
|
|
|
2020-08-02 12:52:11 +02:00
|
|
|
chunked_tbl = chunked.ChunkedUpdate(tbl, "id")
|
2020-03-13 19:00:54 +01:00
|
|
|
chunked_tbl.update(dict(id=1, temp=50))
|
2020-08-02 12:52:11 +02:00
|
|
|
chunked_tbl.update(dict(id=2, location="asdf"))
|
2020-03-13 19:00:54 +01:00
|
|
|
chunked_tbl.update(dict(id=3, temp=50))
|
|
|
|
|
chunked_tbl.flush()
|
|
|
|
|
|
|
|
|
|
# Ensure data has been updated.
|
2020-08-02 12:52:11 +02:00
|
|
|
assert tbl.find_one(id=1)["temp"] == tbl.find_one(id=3)["temp"] == 50
|
|
|
|
|
assert (
|
|
|
|
|
tbl.find_one(id=2)["location"] == tbl.find_one(id=3)["location"] == "asdf"
|
|
|
|
|
) # noqa
|
2020-03-13 19:00:54 +01:00
|
|
|
|
2019-07-08 19:10:00 +02:00
|
|
|
def test_upsert_many(self):
|
|
|
|
|
# Also tests updating on records with different attributes
|
2020-08-02 12:52:11 +02:00
|
|
|
tbl = self.db["upsert_many_test"]
|
2019-07-08 19:10:00 +02:00
|
|
|
|
|
|
|
|
W = 100
|
2020-08-02 12:52:11 +02:00
|
|
|
tbl.upsert_many([dict(age=10), dict(weight=W)], "id")
|
|
|
|
|
assert tbl.find_one(id=1)["age"] == 10
|
2019-07-08 19:10:00 +02:00
|
|
|
|
2020-08-02 12:52:11 +02:00
|
|
|
tbl.upsert_many([dict(id=1, age=70), dict(id=2, weight=W / 2)], "id")
|
|
|
|
|
assert tbl.find_one(id=2)["weight"] == W / 2
|
2019-07-08 19:10:00 +02:00
|
|
|
|
2017-09-03 10:05:17 +02:00
|
|
|
def test_drop_operations(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
assert self.tbl._table is not None, "table shouldn't be dropped yet"
|
2013-04-05 00:47:40 +02:00
|
|
|
self.tbl.drop()
|
2020-08-02 12:52:11 +02:00
|
|
|
assert self.tbl._table is None, "table should be dropped now"
|
2017-09-03 10:05:17 +02:00
|
|
|
assert list(self.tbl.all()) == [], self.tbl.all()
|
|
|
|
|
assert self.tbl.count() == 0, self.tbl.count()
|
2013-04-01 19:56:14 +02:00
|
|
|
|
2016-01-14 21:40:53 +01:00
|
|
|
def test_table_drop(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
assert "weather" in self.db
|
|
|
|
|
self.db["weather"].drop()
|
|
|
|
|
assert "weather" not in self.db
|
2016-01-14 21:40:53 +01:00
|
|
|
|
2017-09-02 22:35:29 +02:00
|
|
|
def test_table_drop_then_create(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
assert "weather" in self.db
|
|
|
|
|
self.db["weather"].drop()
|
|
|
|
|
assert "weather" not in self.db
|
|
|
|
|
self.db["weather"].insert({"foo": "bar"})
|
2017-09-02 22:35:29 +02:00
|
|
|
|
2013-04-05 11:46:45 +02:00
|
|
|
def test_columns(self):
|
|
|
|
|
cols = self.tbl.columns
|
2020-08-02 12:52:11 +02:00
|
|
|
assert len(list(cols)) == 4, "column count mismatch"
|
|
|
|
|
assert "date" in cols and "temperature" in cols and "place" in cols
|
2013-04-05 11:46:45 +02:00
|
|
|
|
2015-06-26 00:53:43 +02:00
|
|
|
def test_drop_column(self):
|
2016-01-18 11:14:30 +01:00
|
|
|
try:
|
2020-08-02 12:52:11 +02:00
|
|
|
self.tbl.drop_column("date")
|
|
|
|
|
assert "date" not in self.tbl.columns
|
2017-09-03 23:23:57 +02:00
|
|
|
except RuntimeError:
|
2016-01-18 11:14:30 +01:00
|
|
|
pass
|
2015-06-26 00:53:43 +02:00
|
|
|
|
2013-04-05 11:46:45 +02:00
|
|
|
def test_iter(self):
|
|
|
|
|
c = 0
|
|
|
|
|
for row in self.tbl:
|
|
|
|
|
c += 1
|
|
|
|
|
assert c == len(self.tbl)
|
|
|
|
|
|
|
|
|
|
def test_update(self):
|
2013-12-18 03:22:00 +01:00
|
|
|
date = datetime(2011, 1, 2)
|
2020-08-02 12:52:11 +02:00
|
|
|
res = self.tbl.update(
|
|
|
|
|
{"date": date, "temperature": -10, "place": TEST_CITY_1}, ["place", "date"]
|
2013-04-05 11:46:45 +02:00
|
|
|
)
|
2020-08-02 12:52:11 +02:00
|
|
|
assert res, "update should return True"
|
2013-12-18 11:33:45 +01:00
|
|
|
m = self.tbl.find_one(place=TEST_CITY_1, date=date)
|
2020-08-02 12:52:11 +02:00
|
|
|
assert m["temperature"] == -10, (
|
|
|
|
|
"new temp. should be -10 but is %d" % m["temperature"]
|
|
|
|
|
)
|
2013-04-01 19:38:02 +02:00
|
|
|
|
2013-04-05 11:58:16 +02:00
|
|
|
def test_create_column(self):
|
|
|
|
|
tbl = self.tbl
|
2020-08-23 12:23:00 +02:00
|
|
|
flt = self.db.types.float
|
|
|
|
|
tbl.create_column("foo", flt)
|
2020-08-02 12:52:11 +02:00
|
|
|
assert "foo" in tbl.table.c, tbl.table.c
|
2020-08-23 12:23:00 +02:00
|
|
|
assert isinstance(tbl.table.c["foo"].type, flt), tbl.table.c["foo"].type
|
2020-08-02 12:52:11 +02:00
|
|
|
assert "foo" in tbl.columns, tbl.columns
|
2013-04-05 11:58:16 +02:00
|
|
|
|
2016-10-21 22:59:17 +02:00
|
|
|
def test_ensure_column(self):
|
|
|
|
|
tbl = self.tbl
|
2020-08-23 12:23:00 +02:00
|
|
|
flt = self.db.types.float
|
2020-08-02 12:52:11 +02:00
|
|
|
tbl.create_column_by_example("foo", 0.1)
|
|
|
|
|
assert "foo" in tbl.table.c, tbl.table.c
|
2020-08-23 12:23:00 +02:00
|
|
|
assert isinstance(tbl.table.c["foo"].type, flt), tbl.table.c["bar"].type
|
2020-08-02 12:52:11 +02:00
|
|
|
tbl.create_column_by_example("bar", 1)
|
|
|
|
|
assert "bar" in tbl.table.c, tbl.table.c
|
|
|
|
|
assert isinstance(tbl.table.c["bar"].type, BIGINT), tbl.table.c["bar"].type
|
|
|
|
|
tbl.create_column_by_example("pippo", "test")
|
|
|
|
|
assert "pippo" in tbl.table.c, tbl.table.c
|
|
|
|
|
assert isinstance(tbl.table.c["pippo"].type, TEXT), tbl.table.c["pippo"].type
|
|
|
|
|
tbl.create_column_by_example("bigbar", 11111111111)
|
|
|
|
|
assert "bigbar" in tbl.table.c, tbl.table.c
|
|
|
|
|
assert isinstance(tbl.table.c["bigbar"].type, BIGINT), tbl.table.c[
|
|
|
|
|
"bigbar"
|
|
|
|
|
].type
|
|
|
|
|
tbl.create_column_by_example("littlebar", -11111111111)
|
|
|
|
|
assert "littlebar" in tbl.table.c, tbl.table.c
|
|
|
|
|
assert isinstance(tbl.table.c["littlebar"].type, BIGINT), tbl.table.c[
|
|
|
|
|
"littlebar"
|
|
|
|
|
].type
|
2016-10-21 22:59:17 +02:00
|
|
|
|
2013-12-19 23:46:10 +01:00
|
|
|
def test_key_order(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
res = self.db.query("SELECT temperature, place FROM weather LIMIT 1")
|
2014-01-05 18:36:11 +01:00
|
|
|
keys = list(res.next().keys())
|
2020-08-02 12:52:11 +02:00
|
|
|
assert keys[0] == "temperature"
|
|
|
|
|
assert keys[1] == "place"
|
2014-02-16 13:48:10 +01:00
|
|
|
|
|
|
|
|
def test_empty_query(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
empty = list(self.tbl.find(place="not in data"))
|
2017-12-05 17:21:08 +01:00
|
|
|
assert len(empty) == 0, empty
|
2015-05-23 16:15:17 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class Constructor(dict):
|
2020-12-29 20:03:45 +01:00
|
|
|
"""Very simple low-functionality extension to ``dict`` to
|
2015-05-23 16:15:17 +02:00
|
|
|
provide attribute access to dictionary contents"""
|
2020-08-02 12:52:11 +02:00
|
|
|
|
2015-05-23 16:15:17 +02:00
|
|
|
def __getattr__(self, name):
|
|
|
|
|
return self[name]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class RowTypeTestCase(unittest.TestCase):
|
|
|
|
|
def setUp(self):
|
2020-06-28 23:06:59 +02:00
|
|
|
self.db = connect(row_type=Constructor)
|
2020-08-02 12:52:11 +02:00
|
|
|
self.tbl = self.db["weather"]
|
2015-05-23 16:15:17 +02:00
|
|
|
for row in TEST_DATA:
|
|
|
|
|
self.tbl.insert(row)
|
|
|
|
|
|
|
|
|
|
def tearDown(self):
|
|
|
|
|
for table in self.db.tables:
|
|
|
|
|
self.db[table].drop()
|
|
|
|
|
|
|
|
|
|
def test_find_one(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
self.tbl.insert(
|
|
|
|
|
{"date": datetime(2011, 1, 2), "temperature": -10, "place": "Berlin"}
|
2015-05-23 16:15:17 +02:00
|
|
|
)
|
2020-08-02 12:52:11 +02:00
|
|
|
d = self.tbl.find_one(place="Berlin")
|
|
|
|
|
assert d["temperature"] == -10, d
|
2015-05-23 16:15:17 +02:00
|
|
|
assert d.temperature == -10, d
|
2020-08-02 12:52:11 +02:00
|
|
|
d = self.tbl.find_one(place="Atlantis")
|
2015-05-23 16:15:17 +02:00
|
|
|
assert d is None, d
|
|
|
|
|
|
|
|
|
|
def test_find(self):
|
|
|
|
|
ds = list(self.tbl.find(place=TEST_CITY_1))
|
|
|
|
|
assert len(ds) == 3, ds
|
|
|
|
|
for item in ds:
|
|
|
|
|
assert isinstance(item, Constructor), item
|
|
|
|
|
ds = list(self.tbl.find(place=TEST_CITY_1, _limit=2))
|
|
|
|
|
assert len(ds) == 2, ds
|
|
|
|
|
for item in ds:
|
|
|
|
|
assert isinstance(item, Constructor), item
|
|
|
|
|
|
|
|
|
|
def test_distinct(self):
|
2020-08-02 12:52:11 +02:00
|
|
|
x = list(self.tbl.distinct("place"))
|
2015-05-23 16:15:17 +02:00
|
|
|
assert len(x) == 2, x
|
|
|
|
|
for item in x:
|
|
|
|
|
assert isinstance(item, Constructor), item
|
2020-08-02 12:52:11 +02:00
|
|
|
x = list(self.tbl.distinct("place", "date"))
|
2015-05-23 16:15:17 +02:00
|
|
|
assert len(x) == 6, x
|
|
|
|
|
for item in x:
|
|
|
|
|
assert isinstance(item, Constructor), item
|
|
|
|
|
|
|
|
|
|
def test_iter(self):
|
|
|
|
|
c = 0
|
|
|
|
|
for row in self.tbl:
|
|
|
|
|
c += 1
|
|
|
|
|
assert isinstance(row, Constructor), row
|
|
|
|
|
assert c == len(self.tbl)
|
2015-06-08 10:04:30 +02:00
|
|
|
|
|
|
|
|
|
2020-08-02 12:52:11 +02:00
|
|
|
if __name__ == "__main__":
|
2015-06-08 10:04:30 +02:00
|
|
|
unittest.main()
|