<commit_before><?php

namespace WeiTest;

use PDO;

/**
 * @property \Wei\Db db
 * @method \Wei\Record db($table = null)
 */
class DbTest extends TestCase
{
    protected function createTable()
    {
        $db = $this->db;
        $db->query("CREATE TABLE prefix_member_group (id INTEGER NOT NULL, name VARCHAR(50) NOT NULL, PRIMARY KEY(id))");
        $db->query("CREATE TABLE prefix_member (id INTEGER NOT NULL, group_id INTEGER NOT NULL, name VARCHAR(50) NOT NULL, address VARCHAR(256) NOT NULL, PRIMARY KEY(id))");
        $db->query("CREATE TABLE prefix_post (id INTEGER NOT NULL, member_id INTEGER NOT NULL, name VARCHAR(50) NOT NULL, PRIMARY KEY(id))");
        $db->query("CREATE TABLE prefix_tag (id INTEGER NOT NULL, name VARCHAR(50) NOT NULL, PRIMARY KEY(id))");
        $db->query("CREATE TABLE prefix_post_tag (post_id INTEGER NOT NULL, tag_id INTEGER NOT NULL)");
    }

    protected function dropTable()
    {
        $db = $this->db;
        $db->query('DROP TABLE IF EXISTS prefix_member_group');
        $db->query('DROP TABLE IF EXISTS prefix_member');
        $db->query('DROP TABLE IF EXISTS prefix_post');
        $db->query('DROP TABLE IF EXISTS prefix_tag');
        $db->query('DROP TABLE IF EXISTS prefix_post_tag');
    }

    public function initFixtures()
    {
        $db = $this->db;

        $db->setOption('tablePrefix', 'prefix_');

        $this->dropTable();
        $this->createTable();

        $db->insert('member_group', array(
            'id' => '1',
            'name' => 'vip'
        ));

        $db->insert('member', array(
            'group_id' => '1',
            'name' => 'twin',
            'address' => 'test'
        ));

        $db->insert('member', array(
            'group_id' => '1',
            'name' => 'test',
            'address' => 'test'
        ));

        $db->insert('post', array(
            'member_id' => '1',
            'name' => 'my first post',
        ));

        $db->insert('post', array(
            'member_id' => '1',
            'name' => 'my second post',
        ));

        $db->insert('tag', array(
            'id' => '1',
            'name' => 'database'
        ));

        $db->insert('tag', array(
            'id' => '2',
            'name' => 'PHP'
        ));

        $db->insert('post_tag', array(
            'post_id' => '1',
            'tag_id' => '1',
        ));

        $db->insert('post_tag', array(
            'post_id' => '1',
            'tag_id' => '2',
        ));

        $db->insert('post_tag', array(
            'post_id' => '2',
            'tag_id' => '1',
        ));
    }

    public function testIsConnected()
    {
        $db = $this->db;

        $db->connect();
        $this->assertTrue($db->isConnected());

        $db->close();
        $this->assertFalse($db->isConnected());
    }

    public function testGetRecord()
    {
        $this->initFixtures();
        $this->assertInstanceOf('\Wei\Record', $this->db->init('member'));
    }

    public function testRelation()
    {
        $this->initFixtures();

        $db = $this->db;

        $db->setOption('recordNamespace', 'WeiTest\Db');

        /** @var $member \WeiTest\Db\Member */
        $member = $this->db('member')->find('1');

        $this->assertInstanceOf('\Wei\Record', $member);

        $this->assertEquals('1', $member['id']);
        $this->assertEquals('twin', $member['name']);
        $this->assertEquals('test', $member['address']);
        $this->assertEquals('1', $member['group_id']);

        // Relation one-to-one
        $post = $member->getPost();

        $this->assertInstanceOf('\Wei\Record', $post);

        $this->assertEquals('1', $post['id']);
        $this->assertEquals('my first post', $post['name']);
        $this->assertEquals('1', $post['member_id']);

        // Relation belong-to
        $group = $member->getGroup();

        $this->assertInstanceOf('\Wei\Record', $group);

        $this->assertEquals('1', $group['id']);
        $this->assertEquals('vip', $group['name']);

        // Relation one-to-many
        $posts = $member->getPosts();

        $this->assertInstanceOf('\Wei\Record', $posts);

        $firstPost = $posts[0];
        $this->assertInstanceOf('\Wei\Record', $firstPost);

        $this->assertEquals('1', $firstPost['id']);
        $this->assertEquals('my first post', $firstPost['name']);
        $this->assertEquals('1', $firstPost['member_id']);
    }

    public function testSet()
    {
        $this->initFixtures();

        $member = $this->db('member')->find('1');

        $this->assertEquals('1', $member['id']);

        $member['id'] = 2;

        $this->assertEquals('2', $member['id']);
    }

    public function testGetRelation()
    {
        $this->initFixtures();

        $member = $this->db('member')->find('1');

        $post = $member->post = $this->db->find('post', array('member_id' => $member['id']));

        $this->assertInstanceOf('\Wei\Record', $post);

        $this->assertEquals('1', $post['id']);
        $this->assertEquals('my first post', $post['name']);
        $this->assertEquals('1', $post['member_id']);
    }

    public function testUpdate()
    {
        $this->initFixtures();

        $this->db->update('member', array('name' => 'hello'), array('id' => '1'));

        $member = $this->db->find('member', '1');

        $this->assertEquals('hello', $member['name']);
    }

    public function testDelete()
    {
        $this->initFixtures();

        $this->db->delete('member', array('id' => '1'));

        $member = $this->db->find('member', 1);

        $this->assertFalse($member);
    }

    public function testFind()
    {
        $this->initFixtures();

        $member = $this->db->find('member', '1');

        $this->assertEquals('1', $member['id']);
    }

    public function testFindOrInit()
    {
        $this->initFixtures();

        $member = $this->db->find('member', '3');
        $this->assertFalse($member);

        // Not found and create new object
        $member = $this->db->findOrInit('member', '3', array(
            'name' => 'name'
        ));
        $this->assertEquals('name', $member['name']);
        $this->assertEquals('3', $member['id']);

        // Found
        $member = $this->db->findOrInit('member', '2');

        $this->assertEquals('2', $member['id']);

        $member = $this->db->findOrInit('member', '3', array(
            'id' => '1', // Would be overwrite
            'name' => 'twin'
        ));

        $this->assertNotEquals('1', $member['id']);
        $this->assertEquals('3', $member['id']);

        $member = $this->db->findOrInit('member', array(
            'group_id' => '1',
            'name' => 'twin2',
        ));

        $this->assertEquals('1', $member['group_id']);
        $this->assertEquals('twin2', $member['name']);
    }

    public function testFindOrInitAndStatusIsNew()
    {
        $this->initFixtures();

        $member = $this->db->findOrInit('member', '3', array(
            'name' => 'name'
        ));
        $this->assertTrue($member->isNew());
        $this->assertFalse($member->isDestroyed());
    }

    public function testRecordSave()
    {
        $this->initFixtures();

        $db = $this->db;

        // Existing member
        $member = $db('member')->find(1);
        $member->address = 'address';
        $result = $member->save();

        $this->assertTrue($result);
        $this->assertEquals('1', $member['id']);

        // New member save with data
        $member = $db->init('member');
        $this->assertTrue($member->isNew());
        $member->fromArray(array(
            'group_id' => '1',
            'name' => 'save',
            'address' => 'save'
        ));
        $result = $member->save();
        $this->assertFalse($member->isNew());

        $this->assertTrue($result);
        $this->assertEquals('3', $member['id']);
        $this->assertEquals('save', $member['name']);

        // Save again
        $member->address = 'address3';
        $result = $member->save();
        $this->assertTrue($result);
        $this->assertEquals('3', $member['id']);
    }

    public function testSelect()
    {
        $this->initFixtures();

        $data = $this->db->select('member', 1);
        $this->assertEquals('twin', $data['name']);

        // Empty array as conditions
        $data = $this->db->select('member', array());
        $this->assertArrayHasKey('name', $data);
    }

    public function testSelectWithField()
    {
        $this->initFixtures();

        $data = $this->db->select('member', 1, 'id, name');

        $this->assertArrayHasKey('id', $data);
        $this->assertArrayHasKey('name', $data);
        $this->assertArrayNotHasKey('group_id', $data);
    }

    public function testSelectAll()
    {
        $this->initFixtures();

        $data = $this->db->selectAll('member', array('name' => 'twin'));

        $this->assertCount(1, $data);

        $data = $this->db->selectAll('member');

        $this->assertCount(2, $data);
    }

    public function testFetch()
    {
        $this->initFixtures();

        $data = $this->db->fetch("SELECT * FROM prefix_member WHERE name = ?", 'twin');
        $this->assertInternalType('array', $data);
        $this->assertEquals('twin', $data['name']);
        $this->assertEquals("SELECT * FROM prefix_member WHERE name = ?", $this->db->getLastQuery());

        $data = $this->db->fetch("SELECT * FROM prefix_member WHERE name = ?", 'notFound');
        $this->assertFalse($data);
        $this->assertEquals("SELECT * FROM prefix_member WHERE name = ?", $this->db->getLastQuery());

        $data = $this->db->fetch("SELECT * FROM prefix_member WHERE name = :name", array('name' => 'twin'));
        $this->assertInternalType('array', $data);
        $this->assertEquals('twin', $data['name']);

        $data = $this->db->fetch("SELECT * FROM prefix_member WHERE name = :name", array(':name' => 'twin'));
        $this->assertInternalType('array', $data);
        $this->assertEquals('twin', $data['name']);
    }

    public function testFetchAll()
    {
        $this->initFixtures();

        $data = $this->db->fetchAll("SELECT * FROM prefix_member WHERE group_id = ?", '1');

        $this->assertInternalType('array', $data);
        $this->assertEquals('1', $data[0]['group_id']);
    }

    public function testQueryFetch()
    {
        $this->initFixtures();

        $data = $this->db('member')->where('id = 1')->fetch();
        $this->assertInternalType('array', $data);
        $this->assertEquals('1', $data['id']);
    }

    public function testQueryFetchAll()
    {
        $this->initFixtures();

        $data = $this->db('member')->fetchAll();

        $this->assertInternalType('array', $data);
        $this->assertEquals('1', $data[0]['group_id']);
    }

    public function testGetRecordClass()
    {
        $db = $this->db;

        $db->setOption('recordNamespace', 'WeiTest\Db');

        $this->assertEquals('WeiTest\Db\Member', $db->getRecordClass('member'));
        $this->assertEquals('WeiTest\Db\Member', $db->getRecordClass('member'));
        $this->assertEquals('WeiTest\Db\MemberGroup', $db->getRecordClass('member_group'));
        $this->assertEquals('WeiTest\Db\MemberGroup', $db->getRecordClass('memberGroup'));
        $this->assertEquals('WeiTest\Db\MemberGroup', $db->getRecordClass('member_Group'));
    }

    /**
     * @link http://edgeguides.rubyonrails.org/active_record_querying.html#conditions
     */
    public function testQuery()
    {
        $this->initFixtures();

        // Pure string conditions
        $query = $this->db('member')->where("name = 'twin'");
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member WHERE name = 'twin' LIMIT 1", $query->getSql());
        $this->assertEquals('twin', $member['name']);

        // ? conditions
        $query = $this->db('member')->where('name = ?', 'twin');
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member WHERE name = ? LIMIT 1", $query->getSql());
        $this->assertEquals('twin', $member['name']);

        $query = $this->db('member')->where('group_id = ? AND name = ?', array('1', 'twin'));
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member WHERE group_id = ? AND name = ? LIMIT 1", $query->getSql());
        $this->assertEquals('1', $member['group_id']);
        $this->assertEquals('twin', $member['name']);

        // : conditions
        $query = $this->db('member')->where('group_id = :groupId AND name = :name', array(
            'groupId' => '1',
            'name' => 'twin'
        ));
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member WHERE group_id = :groupId AND name = :name LIMIT 1", $query->getSql());
        $this->assertEquals('1', $member['group_id']);
        $this->assertEquals('twin', $member['name']);

        $query = $this->db('member')->where('group_id = :groupId AND name = :name', array(
            ':groupId' => '1',
            ':name' => 'twin'
        ));
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member WHERE group_id = :groupId AND name = :name LIMIT 1", $query->getSql());
        $this->assertEquals('1', $member['group_id']);
        $this->assertEquals('twin', $member['name']);

        // Range conditions
        $query = $this->db('member')->where('group_id BETWEEN ? AND ?', array('1', '2'));
        $this->assertEquals("SELECT * FROM prefix_member WHERE group_id BETWEEN ? AND ?", $query->getSql());

        $member = $query->find();
        $this->assertGreaterThanOrEqual(1, $member['group_id']);
        $this->assertLessThanOrEqual(2, $member['group_id']);

        // Subset conditions
        $query = $this->db('member')->where(array('group_id' => array('1', '2')));
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member WHERE group_id IN (?, ?) LIMIT 1", $query->getSql());
        $this->assertEquals('1', $member['group_id']);

        $query = $this->db('member')->where(array(
            'id' => '1',
            'group_id' => array('1', '2')
        ));
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member WHERE id = ? AND group_id IN (?, ?) LIMIT 1", $query->getSql());
        $this->assertEquals('1', $member['id']);

        // Overwrite where
        $query = $this
            ->db('member')
            ->where('id = :id')
            ->where('group_id = :groupId')
            ->setParameter('groupId', 1);
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member WHERE group_id = :groupId LIMIT 1", $query->getSql());
        $this->assertEquals('1', $member['group_id']);

        // Where with empty content
        $query = $this->db('member')->where(array());
        $this->assertEquals("SELECT * FROM prefix_member", $query->getSql());

        // Order
        $query = $this->db('member')->orderBy('id', 'ASC');
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member ORDER BY id ASC LIMIT 1", $query->getSql());
        $this->assertEquals('1', $member['id']);

        // Add order
        $query = $this->db('member')->orderBy('id', 'ASC')->addOrderBy('group_id', 'ASC');
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member ORDER BY id ASC, group_id ASC LIMIT 1", $query->getSql());
        $this->assertEquals('1', $member['id']);

        // Select
        $query = $this->db('member')->select('id, group_id');
        $member = $query->fetch();

        $this->assertEquals("SELECT id, group_id FROM prefix_member LIMIT 1", $query->getSql());
        $this->assertArrayHasKey('id', $member);
        $this->assertArrayHasKey('group_id', $member);
        $this->assertArrayNotHasKey('name', $member);

        // Add select
        $query = $this->db('member')->select('id')->addSelect('group_id');
        $member = $query->fetch();

        $this->assertEquals("SELECT id, group_id FROM prefix_member LIMIT 1", $query->getSql());
        $this->assertArrayHasKey('id', $member);
        $this->assertArrayHasKey('group_id', $member);
        $this->assertArrayNotHasKey('name', $member);

        // Distinct
        $query = $this->db('member')->select('DISTINCT group_id');
        $member = $query->find();

        $this->assertEquals("SELECT DISTINCT group_id FROM prefix_member LIMIT 1", $query->getSql());
        $this->assertEquals('1', $member['group_id']);

        // Limit
        $query = $this->db('member')->limit(2);
        $member = $query->findAll();

        $this->assertEquals("SELECT * FROM prefix_member LIMIT 2", $query->getSql());
        $this->assertCount(2, $member);

        // Offset
        $query = $this->db('member')->limit(1)->offset(1);
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member LIMIT 1 OFFSET 1", $query->getSql());
        $this->assertEquals(2, $member['id']);

        // Page
        $query = $this->db('member')->page(3);
        $this->assertEquals("SELECT * FROM prefix_member LIMIT 10 OFFSET 20", $query->getSql());

        // Mixed limit and page
        $query = $this->db('member')->limit(3)->page(3);
        $this->assertEquals("SELECT * FROM prefix_member LIMIT 3 OFFSET 6", $query->getSql());

        // Group by
        $query = $this->db('member')->groupBy('id, group_id');
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member GROUP BY id, group_id LIMIT 1", $query->getSql());
        $this->assertEquals('1', $member['group_id']);

        // Having
        $query = $this->db('member')->groupBy('id, group_id')->having('group_id >= ?', '1');
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member GROUP BY id, group_id HAVING group_id >= ? LIMIT 1", $query->getSql());
        $this->assertEquals('1', $member['group_id']);

        // Join
        $query = $this
            ->db('member')
            ->select('prefix_member.*, prefix_member_group.name AS group_name')
            ->leftJoin('prefix_member_group', 'prefix_member_group.id = prefix_member.group_id');
        $member = $query->fetch();

        $this->assertEquals("SELECT prefix_member.*, prefix_member_group.name AS group_name FROM prefix_member LEFT JOIN prefix_member_group ON prefix_member_group.id = prefix_member.group_id LIMIT 1", $query->getSql());
        $this->assertArrayHasKey('group_name', $member);

        // Join with table alias
        $query = $this
            ->db('member u')
            ->rightJoin('prefix_member_group g', 'g.id = u.group_id');

        $this->assertEquals("SELECT * FROM prefix_member u RIGHT JOIN prefix_member_group g ON g.id = u.group_id", $query->getSql());
    }

    public function testIndexBy()
    {
        $this->initFixtures();

        $members = $this->db('member')
            ->indexBy('name')
            ->fetchAll();

        $this->assertArrayHasKey('twin', $members);
        $this->assertArrayHasKey('test', $members);

        $members = $this->db('member')
            ->indexBy('name')
            ->findAll();

        $this->assertInstanceOf('\Wei\Record', $members['twin']);
        $this->assertInstanceOf('\Wei\Record', $members['test']);

        $members = $members->toArray();

        $this->assertArrayHasKey('twin', $members);
        $this->assertArrayHasKey('test', $members);
    }

    public function testIndexByException()
    {
        $this->initFixtures();

        $this->setExpectedException('RuntimeException', 'Index field "test" not found in fetched data');
        $members = $this->db('member')
            ->indexBy('test')
            ->fetchAll();
    }

    public function testRealTimeIndexBy()
    {
        $this->initFixtures();

        $members = $this->db('member')->findAll();

        $members = $members->indexBy('name')->toArray();

        $this->assertArrayHasKey('twin', $members);
        $this->assertArrayHasKey('test', $members);
    }

    public function testIndexByExceptionAfterLoaded()
    {
        $this->initFixtures();

        $members = $this->db('member')->findAll();

        $this->setExpectedException('RuntimeException', 'Index field "test" not found in fetched data');

        $members->indexBy('test');
    }

    public function testQueryUpdate()
    {
        $this->initFixtures();

        $member = $this->db('member')->where('id = 1');
        $result = $member->update("name = 'twin2'");

        $this->assertGreaterThan(0, $result);
        $this->assertEquals("UPDATE prefix_member SET name = 'twin2' WHERE id = 1", $member->getSql());

        $member = $this->db->find('member', 1);
        $this->assertEquals(1, $result);
        $this->assertEquals('twin2', $member['name']);
    }

    public function testBindValue()
    {
        $this->initFixtures();

        // Not array parameter
        $member = $this->db->fetch("SELECT * FROM prefix_member WHERE id = ?", 1, PDO::PARAM_INT);

        $this->assertEquals('1', $member['id']);

        // Array parameter
        $member = $this->db->fetch("SELECT * FROM prefix_member WHERE id = ?", array(1), array(PDO::PARAM_INT));

        $this->assertEquals('1', $member['id']);

        $member = $this->db->fetch("SELECT * FROM prefix_member WHERE id = ? AND group_id = ?", array(1, 1), array(
            PDO::PARAM_INT // (no parameter type for second placeholder)
        ));

        $this->assertEquals('1', $member['id']);
        $this->assertEquals('1', $member['group_id']);

        // Name parameter
        $member = $this->db->fetch("SELECT * FROM prefix_member WHERE id = :id", array(
            'id' => 1
        ), array(
            'id' => PDO::PARAM_INT
        ));

        $this->assertEquals('1', $member['id']);

        // Name parameter with colon
        $member = $this->db->fetch("SELECT * FROM prefix_member WHERE id = :id", array(
            'id' => 1
        ), array(
            ':id' => PDO::PARAM_INT
        ));

        $this->assertEquals('1', $member['id']);

        $member = $this->db->fetch("SELECT * FROM prefix_member WHERE id = :id", array(
            'id' => '1'
        ));

        $this->assertEquals('1', $member['id']);
    }

    public function testFetchColumn()
    {
        $this->initFixtures();

        $count = $this->db->fetchColumn("SELECT COUNT(id) FROM prefix_member");
        $this->assertEquals(2, $count);
    }

    public function testRecordNamespace()
    {
        $this->initFixtures();

        $this->db->setOption('recordNamespace', 'WeiTest\Db');

        $member = $this->db->find('member', 1);

        $this->assertEquals('WeiTest\Db\Member', $this->db->getRecordClass('member'));
        $this->assertInstanceOf('WeiTest\Db\Member', $member);
    }

    public function testCustomRecordClass()
    {
        $this->initFixtures();

        $this->db->setOption('recordClasses', array(
            'member' => 'WeiTest\Db\Member'
        ));

        $member = $this->db->find('member', 1);

        $this->assertEquals('WeiTest\Db\Member', $this->db->getRecordClass('member'));
        $this->assertInstanceOf('WeiTest\Db\Member', $member);
    }

    public function testRecordToArray()
    {
        $this->initFixtures();

        $member = $this->db->find('member', 1)->toArray();

        $this->assertInternalType('array', $member);
        $this->assertArrayHasKey('id', $member);
        $this->assertArrayHasKey('group_id', $member);
        $this->assertArrayHasKey('name', $member);
        $this->assertArrayHasKey('address', $member);

        $member = $this->db->find('member', 1)->toArray(array('id', 'group_id'));
        $this->assertInternalType('array', $member);
        $this->assertArrayHasKey('id', $member);
        $this->assertArrayHasKey('group_id', $member);
        $this->assertArrayNotHasKey('name', $member);
        $this->assertArrayNotHasKey('address', $member);

        $member = $this->db->find('member', 1)->toArray(array('id', 'group_id', 'notExistField'));
        $this->assertInternalType('array', $member);
        $this->assertArrayHasKey('id', $member);
        $this->assertArrayHasKey('group_id', $member);
        $this->assertArrayNotHasKey('name', $member);
        $this->assertArrayNotHasKey('address', $member);

        $member = $this->db->init('member')->toArray();
        $this->assertInternalType('array', $member);
        $this->assertArrayHasKey('id', $member);
        $this->assertArrayHasKey('group_id', $member);
        $this->assertArrayHasKey('name', $member);
        $this->assertArrayHasKey('address', $member);
        $this->assertNull($member['id']);
        $this->assertNull($member['group_id']);
        $this->assertNull($member['name']);
        $this->assertNull($member['address']);

        $members = $this->db('member')->findAll()->toArray(array('id', 'group_id'));
        $this->assertInternalType('array', $members);
        $this->assertArrayHasKey(0, $members);
        $this->assertArrayHasKey('id', $members[0]);
        $this->assertArrayHasKey('group_id', $members[0]);
        $this->assertArrayNotHasKey('name', $members[0]);

        $this->db->setOption('recordClasses', array(
            'member' => 'WeiTest\Db\Member'
        ));
    }

    public function testToJson()
    {
        $this->initFixtures();
        $member = $this->db->init('member');
        $this->assertInternalType('string', $member->toJson());
    }

    public function testDestroyRecord()
    {
        $this->initFixtures();

        $member = $this->db->find('member', 1);

        $result = $member->destroy();

        $this->assertTrue($result);

        $member = $this->db->find('member', 1);

        $this->assertFalse($member);
    }

    public function testDestroyByCondition()
    {
        $this->initFixtures();

        $result = $this->db('member')->destroy(2);

        $this->assertFalse($this->db('member')->find(2));
    }

    public function testBeforeAndAfterDestroy()
    {
        $this->initFixtures();

        $member = $this->db->find('member', 1);
        $member->setOption(array(
            'beforeDestroy' => function() {
                echo 'beforeDestroy';
            },
            'afterDestroy' => function() {
                echo 'afterDestroy';
            }
        ));

        $this->expectOutputString('beforeDestroyafterDestroy');
        $member->destroy();
    }

    public function testGetTable()
    {
        $this->initFixtures();

        $member = $this->db('member')->find('1');

        $this->assertEquals('member', $member->getTable());
    }

    public function testFieldNotFound()
    {
        $this->initFixtures();

        $member = $this->db('member')->find('1');

        $this->setExpectedException('\InvalidArgumentException', 'Field "notFound" not found in record class "Wei\Record"');

        $member['notFound'];
    }

    public function testCollection()
    {
        $this->initFixtures();

        $members = $this->db->findAll('member');

        $this->assertInstanceOf('\Wei\Record', $members);

        // ToArray
        $memberArray = $members->toArray();
        $this->assertInternalType('array', $memberArray);
        foreach ($memberArray as $member) {
            $this->assertInternalType('array', $member);
        }

        // Filter
        $firstGroupMembers = $members->filter(function($member){
            if ('1' == $member['group_id']) {
                return true;
            } else {
                return false;
            }
        });

        $this->assertEquals('1', $firstGroupMembers[0]['group_id']);
        $this->assertInstanceOf('\Wei\Record', $firstGroupMembers);
        $this->assertNotSame($members, $firstGroupMembers);
    }

    public function testRecordUnset()
    {
        $this->initFixtures();

        $member = $this->db('member')->find('1');

        $this->assertEquals('twin', $member['name']);
        $this->assertEquals('1', $member['group_id']);

        unset($member['name']);
        $member->remove('group_id');

        $this->assertEquals(null, $member['name']);
        $this->assertEquals(null, $member['group_id']);
    }

    public function testErrorCodeAndInfo()
    {
        $this->db->errorCode();
        $info = $this->db->errorInfo();

        $this->assertArrayHasKey(0, $info);
        $this->assertArrayHasKey(1, $info);
        $this->assertArrayHasKey(1, $info);
    }

    public function testBeforeAndAfterQuery()
    {
        $this->initFixtures();

        $this->expectOutputRegex('/beforeQueryafterQuery/');

        $this->db->setOption(array(
            'beforeQuery' => function(){
                echo 'beforeQuery';
            },
            'afterQuery' => function(){
                echo 'afterQuery';
            }
        ));

        $this->db->find('member', 1);
    }

    public function testBeforeAndAfterQueryForUpdate()
    {
        $this->initFixtures();

        $this->expectOutputString('beforeQueryafterQuery');

        $this->db->setOption(array(
            'beforeQuery' => function(){
                echo 'beforeQuery';
            },
            'afterQuery' => function(){
                echo 'afterQuery';
            }
        ));

        $this->db->executeUpdate("UPDATE prefix_member SET name = 'twin2' WHERE id = 1");

        $this->assertEquals("UPDATE prefix_member SET name = 'twin2' WHERE id = 1", $this->db->getLastQuery());
    }

    public function testException()
    {
        $this->setExpectedException('PDOException');

        $this->db->query("SELECT * FROM noThis table");
    }

    public function testExceptionWithParams()
    {
        $this->setExpectedException('PDOException', 'An exception occurred while executing "SELECT * FROM noThis table WHERE id = ?"');

        $this->db->query("SELECT * FROM noThis table WHERE id = ?", array(1));
    }

    public function testUpdateWithoutParameters()
    {
        $this->initFixtures();

        $result = $this->db->executeUpdate("UPDATE prefix_member SET name = 'twin2' WHERE id = 1");

        $this->assertEquals(1, $result);
    }

    public function testCount()
    {
        $this->initFixtures();

        $count = $this->db('member')->count();

        $this->assertInternalType('int', $count);
        $this->assertEquals(2, $count);

        $count = $this->db('member')->select('id, name')->limit(1)->offset(2)->count();

        $this->assertInternalType('int', $count);
        $this->assertEquals(2, $count);
    }

    public function testParameters()
    {
        $this->initFixtures();

        $db = $this->db;

        $query = $db('member')
            ->where('id = :id AND group_id = :groupId')
            ->setParameters(array(
                'id' => 1,
                'groupId' => 1
            ), array(
                PDO::PARAM_INT,
                PDO::PARAM_INT
            ));
        $member = $query->find();

        $this->assertEquals(array(
            'id' => 1,
            'groupId' => 1
        ), $query->getParameters());

        $this->assertEquals(1, $query->getParameter('id'));
        $this->assertNull($query->getParameter('no'));<commit_msg>added test for count with conditions<commit_after><?php

namespace WeiTest;

use PDO;

/**
 * @property \Wei\Db db
 * @method \Wei\Record db($table = null)
 */
class DbTest extends TestCase
{
    protected function createTable()
    {
        $db = $this->db;
        $db->query("CREATE TABLE prefix_member_group (id INTEGER NOT NULL, name VARCHAR(50) NOT NULL, PRIMARY KEY(id))");
        $db->query("CREATE TABLE prefix_member (id INTEGER NOT NULL, group_id INTEGER NOT NULL, name VARCHAR(50) NOT NULL, address VARCHAR(256) NOT NULL, PRIMARY KEY(id))");
        $db->query("CREATE TABLE prefix_post (id INTEGER NOT NULL, member_id INTEGER NOT NULL, name VARCHAR(50) NOT NULL, PRIMARY KEY(id))");
        $db->query("CREATE TABLE prefix_tag (id INTEGER NOT NULL, name VARCHAR(50) NOT NULL, PRIMARY KEY(id))");
        $db->query("CREATE TABLE prefix_post_tag (post_id INTEGER NOT NULL, tag_id INTEGER NOT NULL)");
    }

    protected function dropTable()
    {
        $db = $this->db;
        $db->query('DROP TABLE IF EXISTS prefix_member_group');
        $db->query('DROP TABLE IF EXISTS prefix_member');
        $db->query('DROP TABLE IF EXISTS prefix_post');
        $db->query('DROP TABLE IF EXISTS prefix_tag');
        $db->query('DROP TABLE IF EXISTS prefix_post_tag');
    }

    public function initFixtures()
    {
        $db = $this->db;

        $db->setOption('tablePrefix', 'prefix_');

        $this->dropTable();
        $this->createTable();

        $db->insert('member_group', array(
            'id' => '1',
            'name' => 'vip'
        ));

        $db->insert('member', array(
            'group_id' => '1',
            'name' => 'twin',
            'address' => 'test'
        ));

        $db->insert('member', array(
            'group_id' => '1',
            'name' => 'test',
            'address' => 'test'
        ));

        $db->insert('post', array(
            'member_id' => '1',
            'name' => 'my first post',
        ));

        $db->insert('post', array(
            'member_id' => '1',
            'name' => 'my second post',
        ));

        $db->insert('tag', array(
            'id' => '1',
            'name' => 'database'
        ));

        $db->insert('tag', array(
            'id' => '2',
            'name' => 'PHP'
        ));

        $db->insert('post_tag', array(
            'post_id' => '1',
            'tag_id' => '1',
        ));

        $db->insert('post_tag', array(
            'post_id' => '1',
            'tag_id' => '2',
        ));

        $db->insert('post_tag', array(
            'post_id' => '2',
            'tag_id' => '1',
        ));
    }

    public function testIsConnected()
    {
        $db = $this->db;

        $db->connect();
        $this->assertTrue($db->isConnected());

        $db->close();
        $this->assertFalse($db->isConnected());
    }

    public function testGetRecord()
    {
        $this->initFixtures();
        $this->assertInstanceOf('\Wei\Record', $this->db->init('member'));
    }

    public function testRelation()
    {
        $this->initFixtures();

        $db = $this->db;

        $db->setOption('recordNamespace', 'WeiTest\Db');

        /** @var $member \WeiTest\Db\Member */
        $member = $this->db('member')->find('1');

        $this->assertInstanceOf('\Wei\Record', $member);

        $this->assertEquals('1', $member['id']);
        $this->assertEquals('twin', $member['name']);
        $this->assertEquals('test', $member['address']);
        $this->assertEquals('1', $member['group_id']);

        // Relation one-to-one
        $post = $member->getPost();

        $this->assertInstanceOf('\Wei\Record', $post);

        $this->assertEquals('1', $post['id']);
        $this->assertEquals('my first post', $post['name']);
        $this->assertEquals('1', $post['member_id']);

        // Relation belong-to
        $group = $member->getGroup();

        $this->assertInstanceOf('\Wei\Record', $group);

        $this->assertEquals('1', $group['id']);
        $this->assertEquals('vip', $group['name']);

        // Relation one-to-many
        $posts = $member->getPosts();

        $this->assertInstanceOf('\Wei\Record', $posts);

        $firstPost = $posts[0];
        $this->assertInstanceOf('\Wei\Record', $firstPost);

        $this->assertEquals('1', $firstPost['id']);
        $this->assertEquals('my first post', $firstPost['name']);
        $this->assertEquals('1', $firstPost['member_id']);
    }

    public function testSet()
    {
        $this->initFixtures();

        $member = $this->db('member')->find('1');

        $this->assertEquals('1', $member['id']);

        $member['id'] = 2;

        $this->assertEquals('2', $member['id']);
    }

    public function testGetRelation()
    {
        $this->initFixtures();

        $member = $this->db('member')->find('1');

        $post = $member->post = $this->db->find('post', array('member_id' => $member['id']));

        $this->assertInstanceOf('\Wei\Record', $post);

        $this->assertEquals('1', $post['id']);
        $this->assertEquals('my first post', $post['name']);
        $this->assertEquals('1', $post['member_id']);
    }

    public function testUpdate()
    {
        $this->initFixtures();

        $this->db->update('member', array('name' => 'hello'), array('id' => '1'));

        $member = $this->db->find('member', '1');

        $this->assertEquals('hello', $member['name']);
    }

    public function testDelete()
    {
        $this->initFixtures();

        $this->db->delete('member', array('id' => '1'));

        $member = $this->db->find('member', 1);

        $this->assertFalse($member);
    }

    public function testFind()
    {
        $this->initFixtures();

        $member = $this->db->find('member', '1');

        $this->assertEquals('1', $member['id']);
    }

    public function testFindOrInit()
    {
        $this->initFixtures();

        $member = $this->db->find('member', '3');
        $this->assertFalse($member);

        // Not found and create new object
        $member = $this->db->findOrInit('member', '3', array(
            'name' => 'name'
        ));
        $this->assertEquals('name', $member['name']);
        $this->assertEquals('3', $member['id']);

        // Found
        $member = $this->db->findOrInit('member', '2');

        $this->assertEquals('2', $member['id']);

        $member = $this->db->findOrInit('member', '3', array(
            'id' => '1', // Would be overwrite
            'name' => 'twin'
        ));

        $this->assertNotEquals('1', $member['id']);
        $this->assertEquals('3', $member['id']);

        $member = $this->db->findOrInit('member', array(
            'group_id' => '1',
            'name' => 'twin2',
        ));

        $this->assertEquals('1', $member['group_id']);
        $this->assertEquals('twin2', $member['name']);
    }

    public function testFindOrInitAndStatusIsNew()
    {
        $this->initFixtures();

        $member = $this->db->findOrInit('member', '3', array(
            'name' => 'name'
        ));
        $this->assertTrue($member->isNew());
        $this->assertFalse($member->isDestroyed());
    }

    public function testRecordSave()
    {
        $this->initFixtures();

        $db = $this->db;

        // Existing member
        $member = $db('member')->find(1);
        $member->address = 'address';
        $result = $member->save();

        $this->assertTrue($result);
        $this->assertEquals('1', $member['id']);

        // New member save with data
        $member = $db->init('member');
        $this->assertTrue($member->isNew());
        $member->fromArray(array(
            'group_id' => '1',
            'name' => 'save',
            'address' => 'save'
        ));
        $result = $member->save();
        $this->assertFalse($member->isNew());

        $this->assertTrue($result);
        $this->assertEquals('3', $member['id']);
        $this->assertEquals('save', $member['name']);

        // Save again
        $member->address = 'address3';
        $result = $member->save();
        $this->assertTrue($result);
        $this->assertEquals('3', $member['id']);
    }

    public function testSelect()
    {
        $this->initFixtures();

        $data = $this->db->select('member', 1);
        $this->assertEquals('twin', $data['name']);

        // Empty array as conditions
        $data = $this->db->select('member', array());
        $this->assertArrayHasKey('name', $data);
    }

    public function testSelectWithField()
    {
        $this->initFixtures();

        $data = $this->db->select('member', 1, 'id, name');

        $this->assertArrayHasKey('id', $data);
        $this->assertArrayHasKey('name', $data);
        $this->assertArrayNotHasKey('group_id', $data);
    }

    public function testSelectAll()
    {
        $this->initFixtures();

        $data = $this->db->selectAll('member', array('name' => 'twin'));

        $this->assertCount(1, $data);

        $data = $this->db->selectAll('member');

        $this->assertCount(2, $data);
    }

    public function testFetch()
    {
        $this->initFixtures();

        $data = $this->db->fetch("SELECT * FROM prefix_member WHERE name = ?", 'twin');
        $this->assertInternalType('array', $data);
        $this->assertEquals('twin', $data['name']);
        $this->assertEquals("SELECT * FROM prefix_member WHERE name = ?", $this->db->getLastQuery());

        $data = $this->db->fetch("SELECT * FROM prefix_member WHERE name = ?", 'notFound');
        $this->assertFalse($data);
        $this->assertEquals("SELECT * FROM prefix_member WHERE name = ?", $this->db->getLastQuery());

        $data = $this->db->fetch("SELECT * FROM prefix_member WHERE name = :name", array('name' => 'twin'));
        $this->assertInternalType('array', $data);
        $this->assertEquals('twin', $data['name']);

        $data = $this->db->fetch("SELECT * FROM prefix_member WHERE name = :name", array(':name' => 'twin'));
        $this->assertInternalType('array', $data);
        $this->assertEquals('twin', $data['name']);
    }

    public function testFetchAll()
    {
        $this->initFixtures();

        $data = $this->db->fetchAll("SELECT * FROM prefix_member WHERE group_id = ?", '1');

        $this->assertInternalType('array', $data);
        $this->assertEquals('1', $data[0]['group_id']);
    }

    public function testQueryFetch()
    {
        $this->initFixtures();

        $data = $this->db('member')->where('id = 1')->fetch();
        $this->assertInternalType('array', $data);
        $this->assertEquals('1', $data['id']);
    }

    public function testQueryFetchAll()
    {
        $this->initFixtures();

        $data = $this->db('member')->fetchAll();

        $this->assertInternalType('array', $data);
        $this->assertEquals('1', $data[0]['group_id']);
    }

    public function testGetRecordClass()
    {
        $db = $this->db;

        $db->setOption('recordNamespace', 'WeiTest\Db');

        $this->assertEquals('WeiTest\Db\Member', $db->getRecordClass('member'));
        $this->assertEquals('WeiTest\Db\Member', $db->getRecordClass('member'));
        $this->assertEquals('WeiTest\Db\MemberGroup', $db->getRecordClass('member_group'));
        $this->assertEquals('WeiTest\Db\MemberGroup', $db->getRecordClass('memberGroup'));
        $this->assertEquals('WeiTest\Db\MemberGroup', $db->getRecordClass('member_Group'));
    }

    /**
     * @link http://edgeguides.rubyonrails.org/active_record_querying.html#conditions
     */
    public function testQuery()
    {
        $this->initFixtures();

        // Pure string conditions
        $query = $this->db('member')->where("name = 'twin'");
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member WHERE name = 'twin' LIMIT 1", $query->getSql());
        $this->assertEquals('twin', $member['name']);

        // ? conditions
        $query = $this->db('member')->where('name = ?', 'twin');
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member WHERE name = ? LIMIT 1", $query->getSql());
        $this->assertEquals('twin', $member['name']);

        $query = $this->db('member')->where('group_id = ? AND name = ?', array('1', 'twin'));
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member WHERE group_id = ? AND name = ? LIMIT 1", $query->getSql());
        $this->assertEquals('1', $member['group_id']);
        $this->assertEquals('twin', $member['name']);

        // : conditions
        $query = $this->db('member')->where('group_id = :groupId AND name = :name', array(
            'groupId' => '1',
            'name' => 'twin'
        ));
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member WHERE group_id = :groupId AND name = :name LIMIT 1", $query->getSql());
        $this->assertEquals('1', $member['group_id']);
        $this->assertEquals('twin', $member['name']);

        $query = $this->db('member')->where('group_id = :groupId AND name = :name', array(
            ':groupId' => '1',
            ':name' => 'twin'
        ));
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member WHERE group_id = :groupId AND name = :name LIMIT 1", $query->getSql());
        $this->assertEquals('1', $member['group_id']);
        $this->assertEquals('twin', $member['name']);

        // Range conditions
        $query = $this->db('member')->where('group_id BETWEEN ? AND ?', array('1', '2'));
        $this->assertEquals("SELECT * FROM prefix_member WHERE group_id BETWEEN ? AND ?", $query->getSql());

        $member = $query->find();
        $this->assertGreaterThanOrEqual(1, $member['group_id']);
        $this->assertLessThanOrEqual(2, $member['group_id']);

        // Subset conditions
        $query = $this->db('member')->where(array('group_id' => array('1', '2')));
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member WHERE group_id IN (?, ?) LIMIT 1", $query->getSql());
        $this->assertEquals('1', $member['group_id']);

        $query = $this->db('member')->where(array(
            'id' => '1',
            'group_id' => array('1', '2')
        ));
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member WHERE id = ? AND group_id IN (?, ?) LIMIT 1", $query->getSql());
        $this->assertEquals('1', $member['id']);

        // Overwrite where
        $query = $this
            ->db('member')
            ->where('id = :id')
            ->where('group_id = :groupId')
            ->setParameter('groupId', 1);
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member WHERE group_id = :groupId LIMIT 1", $query->getSql());
        $this->assertEquals('1', $member['group_id']);

        // Where with empty content
        $query = $this->db('member')->where(array());
        $this->assertEquals("SELECT * FROM prefix_member", $query->getSql());

        // Order
        $query = $this->db('member')->orderBy('id', 'ASC');
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member ORDER BY id ASC LIMIT 1", $query->getSql());
        $this->assertEquals('1', $member['id']);

        // Add order
        $query = $this->db('member')->orderBy('id', 'ASC')->addOrderBy('group_id', 'ASC');
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member ORDER BY id ASC, group_id ASC LIMIT 1", $query->getSql());
        $this->assertEquals('1', $member['id']);

        // Select
        $query = $this->db('member')->select('id, group_id');
        $member = $query->fetch();

        $this->assertEquals("SELECT id, group_id FROM prefix_member LIMIT 1", $query->getSql());
        $this->assertArrayHasKey('id', $member);
        $this->assertArrayHasKey('group_id', $member);
        $this->assertArrayNotHasKey('name', $member);

        // Add select
        $query = $this->db('member')->select('id')->addSelect('group_id');
        $member = $query->fetch();

        $this->assertEquals("SELECT id, group_id FROM prefix_member LIMIT 1", $query->getSql());
        $this->assertArrayHasKey('id', $member);
        $this->assertArrayHasKey('group_id', $member);
        $this->assertArrayNotHasKey('name', $member);

        // Distinct
        $query = $this->db('member')->select('DISTINCT group_id');
        $member = $query->find();

        $this->assertEquals("SELECT DISTINCT group_id FROM prefix_member LIMIT 1", $query->getSql());
        $this->assertEquals('1', $member['group_id']);

        // Limit
        $query = $this->db('member')->limit(2);
        $member = $query->findAll();

        $this->assertEquals("SELECT * FROM prefix_member LIMIT 2", $query->getSql());
        $this->assertCount(2, $member);

        // Offset
        $query = $this->db('member')->limit(1)->offset(1);
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member LIMIT 1 OFFSET 1", $query->getSql());
        $this->assertEquals(2, $member['id']);

        // Page
        $query = $this->db('member')->page(3);
        $this->assertEquals("SELECT * FROM prefix_member LIMIT 10 OFFSET 20", $query->getSql());

        // Mixed limit and page
        $query = $this->db('member')->limit(3)->page(3);
        $this->assertEquals("SELECT * FROM prefix_member LIMIT 3 OFFSET 6", $query->getSql());

        // Group by
        $query = $this->db('member')->groupBy('id, group_id');
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member GROUP BY id, group_id LIMIT 1", $query->getSql());
        $this->assertEquals('1', $member['group_id']);

        // Having
        $query = $this->db('member')->groupBy('id, group_id')->having('group_id >= ?', '1');
        $member = $query->find();

        $this->assertEquals("SELECT * FROM prefix_member GROUP BY id, group_id HAVING group_id >= ? LIMIT 1", $query->getSql());
        $this->assertEquals('1', $member['group_id']);

        // Join
        $query = $this
            ->db('member')
            ->select('prefix_member.*, prefix_member_group.name AS group_name')
            ->leftJoin('prefix_member_group', 'prefix_member_group.id = prefix_member.group_id');
        $member = $query->fetch();

        $this->assertEquals("SELECT prefix_member.*, prefix_member_group.name AS group_name FROM prefix_member LEFT JOIN prefix_member_group ON prefix_member_group.id = prefix_member.group_id LIMIT 1", $query->getSql());
        $this->assertArrayHasKey('group_name', $member);

        // Join with table alias
        $query = $this
            ->db('member u')
            ->rightJoin('prefix_member_group g', 'g.id = u.group_id');

        $this->assertEquals("SELECT * FROM prefix_member u RIGHT JOIN prefix_member_group g ON g.id = u.group_id", $query->getSql());
    }

    public function testIndexBy()
    {
        $this->initFixtures();

        $members = $this->db('member')
            ->indexBy('name')
            ->fetchAll();

        $this->assertArrayHasKey('twin', $members);
        $this->assertArrayHasKey('test', $members);

        $members = $this->db('member')
            ->indexBy('name')
            ->findAll();

        $this->assertInstanceOf('\Wei\Record', $members['twin']);
        $this->assertInstanceOf('\Wei\Record', $members['test']);

        $members = $members->toArray();

        $this->assertArrayHasKey('twin', $members);
        $this->assertArrayHasKey('test', $members);
    }

    public function testIndexByException()
    {
        $this->initFixtures();

        $this->setExpectedException('RuntimeException', 'Index field "test" not found in fetched data');
        $members = $this->db('member')
            ->indexBy('test')
            ->fetchAll();
    }

    public function testRealTimeIndexBy()
    {
        $this->initFixtures();

        $members = $this->db('member')->findAll();

        $members = $members->indexBy('name')->toArray();

        $this->assertArrayHasKey('twin', $members);
        $this->assertArrayHasKey('test', $members);
    }

    public function testIndexByExceptionAfterLoaded()
    {
        $this->initFixtures();

        $members = $this->db('member')->findAll();

        $this->setExpectedException('RuntimeException', 'Index field "test" not found in fetched data');

        $members->indexBy('test');
    }

    public function testQueryUpdate()
    {
        $this->initFixtures();

        $member = $this->db('member')->where('id = 1');
        $result = $member->update("name = 'twin2'");

        $this->assertGreaterThan(0, $result);
        $this->assertEquals("UPDATE prefix_member SET name = 'twin2' WHERE id = 1", $member->getSql());

        $member = $this->db->find('member', 1);
        $this->assertEquals(1, $result);
        $this->assertEquals('twin2', $member['name']);
    }

    public function testBindValue()
    {
        $this->initFixtures();

        // Not array parameter
        $member = $this->db->fetch("SELECT * FROM prefix_member WHERE id = ?", 1, PDO::PARAM_INT);

        $this->assertEquals('1', $member['id']);

        // Array parameter
        $member = $this->db->fetch("SELECT * FROM prefix_member WHERE id = ?", array(1), array(PDO::PARAM_INT));

        $this->assertEquals('1', $member['id']);

        $member = $this->db->fetch("SELECT * FROM prefix_member WHERE id = ? AND group_id = ?", array(1, 1), array(
            PDO::PARAM_INT // (no parameter type for second placeholder)
        ));

        $this->assertEquals('1', $member['id']);
        $this->assertEquals('1', $member['group_id']);

        // Name parameter
        $member = $this->db->fetch("SELECT * FROM prefix_member WHERE id = :id", array(
            'id' => 1
        ), array(
            'id' => PDO::PARAM_INT
        ));

        $this->assertEquals('1', $member['id']);

        // Name parameter with colon
        $member = $this->db->fetch("SELECT * FROM prefix_member WHERE id = :id", array(
            'id' => 1
        ), array(
            ':id' => PDO::PARAM_INT
        ));

        $this->assertEquals('1', $member['id']);

        $member = $this->db->fetch("SELECT * FROM prefix_member WHERE id = :id", array(
            'id' => '1'
        ));

        $this->assertEquals('1', $member['id']);
    }

    public function testFetchColumn()
    {
        $this->initFixtures();

        $count = $this->db->fetchColumn("SELECT COUNT(id) FROM prefix_member");
        $this->assertEquals(2, $count);
    }

    public function testRecordNamespace()
    {
        $this->initFixtures();

        $this->db->setOption('recordNamespace', 'WeiTest\Db');

        $member = $this->db->find('member', 1);

        $this->assertEquals('WeiTest\Db\Member', $this->db->getRecordClass('member'));
        $this->assertInstanceOf('WeiTest\Db\Member', $member);
    }

    public function testCustomRecordClass()
    {
        $this->initFixtures();

        $this->db->setOption('recordClasses', array(
            'member' => 'WeiTest\Db\Member'
        ));

        $member = $this->db->find('member', 1);

        $this->assertEquals('WeiTest\Db\Member', $this->db->getRecordClass('member'));
        $this->assertInstanceOf('WeiTest\Db\Member', $member);
    }

    public function testRecordToArray()
    {
        $this->initFixtures();

        $member = $this->db->find('member', 1)->toArray();

        $this->assertInternalType('array', $member);
        $this->assertArrayHasKey('id', $member);
        $this->assertArrayHasKey('group_id', $member);
        $this->assertArrayHasKey('name', $member);
        $this->assertArrayHasKey('address', $member);

        $member = $this->db->find('member', 1)->toArray(array('id', 'group_id'));
        $this->assertInternalType('array', $member);
        $this->assertArrayHasKey('id', $member);
        $this->assertArrayHasKey('group_id', $member);
        $this->assertArrayNotHasKey('name', $member);
        $this->assertArrayNotHasKey('address', $member);

        $member = $this->db->find('member', 1)->toArray(array('id', 'group_id', 'notExistField'));
        $this->assertInternalType('array', $member);
        $this->assertArrayHasKey('id', $member);
        $this->assertArrayHasKey('group_id', $member);
        $this->assertArrayNotHasKey('name', $member);
        $this->assertArrayNotHasKey('address', $member);

        $member = $this->db->init('member')->toArray();
        $this->assertInternalType('array', $member);
        $this->assertArrayHasKey('id', $member);
        $this->assertArrayHasKey('group_id', $member);
        $this->assertArrayHasKey('name', $member);
        $this->assertArrayHasKey('address', $member);
        $this->assertNull($member['id']);
        $this->assertNull($member['group_id']);
        $this->assertNull($member['name']);
        $this->assertNull($member['address']);

        $members = $this->db('member')->findAll()->toArray(array('id', 'group_id'));
        $this->assertInternalType('array', $members);
        $this->assertArrayHasKey(0, $members);
        $this->assertArrayHasKey('id', $members[0]);
        $this->assertArrayHasKey('group_id', $members[0]);
        $this->assertArrayNotHasKey('name', $members[0]);

        $this->db->setOption('recordClasses', array(
            'member' => 'WeiTest\Db\Member'
        ));
    }

    public function testToJson()
    {
        $this->initFixtures();
        $member = $this->db->init('member');
        $this->assertInternalType('string', $member->toJson());
    }

    public function testDestroyRecord()
    {
        $this->initFixtures();

        $member = $this->db->find('member', 1);

        $result = $member->destroy();

        $this->assertTrue($result);

        $member = $this->db->find('member', 1);

        $this->assertFalse($member);
    }

    public function testDestroyByCondition()
    {
        $this->initFixtures();

        $result = $this->db('member')->destroy(2);

        $this->assertFalse($this->db('member')->find(2));
    }

    public function testBeforeAndAfterDestroy()
    {
        $this->initFixtures();

        $member = $this->db->find('member', 1);
        $member->setOption(array(
            'beforeDestroy' => function() {
                echo 'beforeDestroy';
            },
            'afterDestroy' => function() {
                echo 'afterDestroy';
            }
        ));

        $this->expectOutputString('beforeDestroyafterDestroy');
        $member->destroy();
    }

    public function testGetTable()
    {
        $this->initFixtures();

        $member = $this->db('member')->find('1');

        $this->assertEquals('member', $member->getTable());
    }

    public function testFieldNotFound()
    {
        $this->initFixtures();

        $member = $this->db('member')->find('1');

        $this->setExpectedException('\InvalidArgumentException', 'Field "notFound" not found in record class "Wei\Record"');

        $member['notFound'];
    }

    public function testCollection()
    {
        $this->initFixtures();

        $members = $this->db->findAll('member');

        $this->assertInstanceOf('\Wei\Record', $members);

        // ToArray
        $memberArray = $members->toArray();
        $this->assertInternalType('array', $memberArray);
        foreach ($memberArray as $member) {
            $this->assertInternalType('array', $member);
        }

        // Filter
        $firstGroupMembers = $members->filter(function($member){
            if ('1' == $member['group_id']) {
                return true;
            } else {
                return false;
            }
        });

        $this->assertEquals('1', $firstGroupMembers[0]['group_id']);
        $this->assertInstanceOf('\Wei\Record', $firstGroupMembers);
        $this->assertNotSame($members, $firstGroupMembers);
    }

    public function testRecordUnset()
    {
        $this->initFixtures();

        $member = $this->db('member')->find('1');

        $this->assertEquals('twin', $member['name']);
        $this->assertEquals('1', $member['group_id']);

        unset($member['name']);
        $member->remove('group_id');

        $this->assertEquals(null, $member['name']);
        $this->assertEquals(null, $member['group_id']);
    }

    public function testErrorCodeAndInfo()
    {
        $this->db->errorCode();
        $info = $this->db->errorInfo();

        $this->assertArrayHasKey(0, $info);
        $this->assertArrayHasKey(1, $info);
        $this->assertArrayHasKey(1, $info);
    }

    public function testBeforeAndAfterQuery()
    {
        $this->initFixtures();

        $this->expectOutputRegex('/beforeQueryafterQuery/');

        $this->db->setOption(array(
            'beforeQuery' => function(){
                echo 'beforeQuery';
            },
            'afterQuery' => function(){
                echo 'afterQuery';
            }
        ));

        $this->db->find('member', 1);
    }

    public function testBeforeAndAfterQueryForUpdate()
    {
        $this->initFixtures();

        $this->expectOutputString('beforeQueryafterQuery');

        $this->db->setOption(array(
            'beforeQuery' => function(){
                echo 'beforeQuery';
            },
            'afterQuery' => function(){
                echo 'afterQuery';
            }
        ));

        $this->db->executeUpdate("UPDATE prefix_member SET name = 'twin2' WHERE id = 1");

        $this->assertEquals("UPDATE prefix_member SET name = 'twin2' WHERE id = 1", $this->db->getLastQuery());
    }

    public function testException()
    {
        $this->setExpectedException('PDOException');

        $this->db->query("SELECT * FROM noThis table");
    }

    public function testExceptionWithParams()
    {
        $this->setExpectedException('PDOException', 'An exception occurred while executing "SELECT * FROM noThis table WHERE id = ?"');

        $this->db->query("SELECT * FROM noThis table WHERE id = ?", array(1));
    }

    public function testUpdateWithoutParameters()
    {
        $this->initFixtures();

        $result = $this->db->executeUpdate("UPDATE prefix_member SET name = 'twin2' WHERE id = 1");

        $this->assertEquals(1, $result);
    }

    public function testCount()
    {
        $this->initFixtures();

        $count = $this->db('member')->count();

        $this->assertInternalType('int', $count);
        $this->assertEquals(2, $count);

        $count = $this->db('member')->select('id, name')->limit(1)->offset(2)->count();

        $this->assertInternalType('int', $count);
        $this->assertEquals(2, $count);
    }

    public function testCountWithCondition()
    {
        $this->initFixtures();

        $count = $this->db('member')->count(1);
        $this->assertInternalType('int', $count);
        $this->assertEquals(1, $count);

        $count = $this->db('member')->count(array('id' => 1));
        $this->assertInternalType('int', $count);
        $this->assertEquals(1, $count);
    }

    public function testParameters()
    {
        $this->initFixtures();

        $db = $this->db;

        $query = $db('member')
            ->where('id = :id AND group_id = :groupId')
            ->setParameters(array(
                'id' => 1,
                'groupId' => 1
            ), array(
                PDO::PARAM_INT,
                PDO::PARAM_INT
            ));
        $member = $query->find();

        $this->assertEquals(array(
            'id' => 1,
            'groupId' => 1
        ), $query->getParameters());

        $this->assertEquals(1, $query->getParameter('id'));
        $this->assertNull($query->getParameter('no'));
{'fraction_non_alphanumeric': 0.1950670869833827, 'fraction_numerical': 0.006399797234147037, 'mean_word_length': 2.5036075036075034, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 1333, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '474953', 'n_tokens_mistral': 19023, 'n_tokens_neox': 18290, 'n_words': 3387}