* @license MIT */ declare(strict_types=1); use BitBadger\PDODocument\{Custom, Delete, Document, DocumentException, Field, FieldMatch, Json}; use Test\Integration\ArrayDocument; use Test\Integration\SQLite\ThrowawayDb; pest()->group('integration', 'sqlite'); /** JSON for document ID "one" */ const ONE = '{"id":"one","value":"FIRST!","num_value":0,"sub":null}'; /** JSON for document ID "two" */ const TWO = '{"id":"two","value":"another","num_value":10,"sub":{"foo":"green","bar":"blue"}}'; /** JSON for document ID "three" */ const THREE = '{"id":"three","value":"","num_value":4,"sub":null}'; /** JSON for document ID "four" */ const FOUR = '{"id":"four","value":"purple","num_value":17,"sub":{"foo":"green","bar":"red"}}'; /** JSON for document ID "five" */ const FIVE = '{"id":"five","value":"purple","num_value":18,"sub":null}'; describe('::all()', function () { test('retrieves data', function () { expect(Json::all(ThrowawayDb::TABLE))->toStartWith('[')->toContain(ONE, TWO, THREE, FOUR, FIVE)->toEndWith(']'); }); test('sorts data ascending', function () { expect(Json::all(ThrowawayDb::TABLE, [Field::named('id')])) ->toBe('[' . implode(',', [FIVE, FOUR, ONE, THREE, TWO]) . ']'); }); test('sorts data descending', function () { expect(Json::all(ThrowawayDb::TABLE, [Field::named('id DESC')])) ->toBe('[' . implode(',', [TWO, THREE, ONE, FOUR, FIVE]) . ']'); }); test('sorts data numerically', function () { expect(Json::all(ThrowawayDb::TABLE, [Field::named('sub.foo NULLS LAST'), Field::named('n:num_value')])) ->toBe('[' . implode(',', [TWO, FOUR, ONE, THREE, FIVE]) . ']'); }); test('returns an empty array when no data exists', function () { Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); expect(Json::all(ThrowawayDb::TABLE))->toBe('[]'); }); }); describe('::byId()', function () { test('returns a document when it exists', function () { expect(Json::byId(ThrowawayDb::TABLE, 'two'))->toBe(TWO); }); test('returns a document with a numeric ID', function () { Document::insert(ThrowawayDb::TABLE, ['id' => 18, 'value' => 'howdy']); expect(Json::byId(ThrowawayDb::TABLE, 18))->toBe('{"id":18,"value":"howdy"}'); }); test('returns "{}" when no document exists', function () { expect(Json::byId(ThrowawayDb::TABLE, 'seventy-five'))->toBe('{}'); }); }); describe('::byFields()', function () { test('returns matching documents', function () { expect(Json::byFields(ThrowawayDb::TABLE, [Field::in('value', ['blue', 'purple']), Field::exists('sub')], FieldMatch::All)) ->toBe('[' . FOUR . ']'); }); test('returns ordered matching documents', function () { expect(Json::byFields(ThrowawayDb::TABLE, [Field::equal('value', 'purple')], FieldMatch::All, [Field::named('id')])) ->toBe('[' . implode(',', [FIVE, FOUR]) . ']'); }); test('returns documents matching numeric IN clause', function () { expect(Json::byFields(ThrowawayDb::TABLE, [Field::in('num_value', [2, 4, 6, 8])]))->toBe('[' . THREE . ']'); }); test('returns empty array when no documents match', function () { expect(Json::byFields(ThrowawayDb::TABLE, [Field::greater('num_value', 100)]))->toBe('[]'); }); test('returns matching documents for inArray comparison', function () { Delete::byFields(ThrowawayDb::TABLE, [Field::notExists('absentField')]); foreach (ArrayDocument::testDocuments() as $doc) Document::insert(ThrowawayDb::TABLE, $doc); expect(Json::byFields(ThrowawayDb::TABLE, [Field::inArray('values', ThrowawayDb::TABLE, ['c'])])) ->toBe('[{"id":"first","values":["a","b","c"]},{"id":"second","values":["c","d","e"]}]'); }); test('returns empty array when no documents match inArray comparison', function () { Delete::byFields(ThrowawayDb::TABLE, [Field::notExists('absentField')]); foreach (ArrayDocument::testDocuments() as $doc) Document::insert(ThrowawayDb::TABLE, $doc); expect(Json::byFields(ThrowawayDb::TABLE, [Field::inArray('values', ThrowawayDb::TABLE, ['j'])]))->toBe('[]'); }); }); describe('::byContains()', function () { test('throws an exception', function () { expect(fn () => Json::byContains('', []))->toThrow(DocumentException::class); }); }); describe('::byJsonPath()', function () { test('throws an exception', function () { expect(fn () => Json::byJsonPath('', ''))->toThrow(DocumentException::class); }); }); describe('::firstByFields()', function () { test('returns a matching document', function () { expect(Json::firstByFields(ThrowawayDb::TABLE, [Field::equal('value', 'another')]))->toBe(TWO); }); test('returns one of several matching documents', function () { $doc = Json::firstByFields(ThrowawayDb::TABLE, [Field::equal('sub.foo', 'green')]); expect($doc == TWO || $doc == FOUR)->toBeTrue("Document should have been two or four (actual $doc)"); }); test('returns first of ordered matching documents', function () { expect(Json::firstByFields(ThrowawayDb::TABLE, [Field::equal('sub.foo', 'green')], orderBy: [Field::named('n:num_value DESC')])) ->toBe(FOUR); }); test('returns "{}" when no documents match', function () { expect(Json::firstByFields(ThrowawayDb::TABLE, [Field::equal('value', 'absent')]))->toBe('{}'); }); }); describe('::firstByContains()', function () { test('throws an exception', function () { expect(fn () => Json::firstByContains('', []))->toThrow(DocumentException::class); }); }); describe('::firstByJsonPath()', function () { test('throws an exception', function () { expect(fn () => Json::firstByJsonPath('', ''))->toThrow(DocumentException::class); }); }); describe('::outputAll()', function () { test('outputs data', function () { $this->clearBuffer(); Json::outputAll(ThrowawayDb::TABLE); expect($this->getBufferContents())->toStartWith('[')->toContain(ONE, TWO, THREE, FOUR, FIVE)->toEndWith(']'); }); test('sorts data ascending', function () { $this->clearBuffer(); Json::outputAll(ThrowawayDb::TABLE, [Field::named('id')]); expect($this->getBufferContents())->toBe('[' . implode(',', [FIVE, FOUR, ONE, THREE, TWO]) . ']'); }); test('sorts data descending', function () { $this->clearBuffer(); Json::outputAll(ThrowawayDb::TABLE, [Field::named('id DESC')]); expect($this->getBufferContents())->toBe('[' . implode(',', [TWO, THREE, ONE, FOUR, FIVE]) . ']'); }); test('sorts data numerically', function () { $this->clearBuffer(); Json::outputAll(ThrowawayDb::TABLE, [Field::named('sub.foo NULLS LAST'), Field::named('n:num_value')]); expect($this->getBufferContents())->toBe('[' . implode(',', [TWO, FOUR, ONE, THREE, FIVE]) . ']'); }); test('outputs an empty array when no data exists', function () { $this->clearBuffer(); Custom::nonQuery('DELETE FROM ' . ThrowawayDb::TABLE, []); Json::outputAll(ThrowawayDb::TABLE); expect($this->getBufferContents())->toBe('[]'); }); }); describe('::outputById()', function () { test('outputs a document when it exists', function () { $this->clearBuffer(); Json::outputById(ThrowawayDb::TABLE, 'two'); expect($this->getBufferContents())->toBe(TWO); }); test('outputs a document with a numeric ID', function () { $this->clearBuffer(); Document::insert(ThrowawayDb::TABLE, ['id' => 18, 'value' => 'howdy']); Json::outputById(ThrowawayDb::TABLE, 18); expect($this->getBufferContents())->toBe('{"id":18,"value":"howdy"}'); }); test('outputs "{}" when no document exists', function () { $this->clearBuffer(); Json::outputById(ThrowawayDb::TABLE, 'seventy-five'); expect($this->getBufferContents())->toBe('{}'); }); }); describe('::outputByFields()', function () { test('outputs matching documents', function () { $this->clearBuffer(); Json::outputByFields(ThrowawayDb::TABLE, [Field::in('value', ['blue', 'purple']), Field::exists('sub')], FieldMatch::All); expect($this->getBufferContents())->toBe('[' . FOUR . ']'); }); test('outputs ordered matching documents', function () { $this->clearBuffer(); Json::outputByFields(ThrowawayDb::TABLE, [Field::equal('value', 'purple')], FieldMatch::All, [Field::named('id')]); expect($this->getBufferContents())->toBe('[' . implode(',', [FIVE, FOUR]) . ']'); }); test('outputs documents matching numeric IN clause', function () { $this->clearBuffer(); Json::outputByFields(ThrowawayDb::TABLE, [Field::in('num_value', [2, 4, 6, 8])]); expect($this->getBufferContents())->toBe('[' . THREE . ']'); }); test('outputs empty array when no documents match', function () { $this->clearBuffer(); Json::outputByFields(ThrowawayDb::TABLE, [Field::greater('num_value', 100)]); expect($this->getBufferContents())->toBe('[]'); }); test('outputs matching documents for inArray comparison', function () { $this->clearBuffer(); Delete::byFields(ThrowawayDb::TABLE, [Field::notExists('absentField')]); foreach (ArrayDocument::testDocuments() as $doc) Document::insert(ThrowawayDb::TABLE, $doc); Json::outputByFields(ThrowawayDb::TABLE, [Field::inArray('values', ThrowawayDb::TABLE, ['c'])]); expect($this->getBufferContents()) ->toBe('[{"id":"first","values":["a","b","c"]},{"id":"second","values":["c","d","e"]}]'); }); test('outputs empty array when no documents match inArray comparison', function () { $this->clearBuffer(); Delete::byFields(ThrowawayDb::TABLE, [Field::notExists('absentField')]); foreach (ArrayDocument::testDocuments() as $doc) Document::insert(ThrowawayDb::TABLE, $doc); Json::outputByFields(ThrowawayDb::TABLE, [Field::inArray('values', ThrowawayDb::TABLE, ['j'])]); expect($this->getBufferContents())->toBe('[]'); }); }); describe('::outputByContains()', function () { test('throws an exception', function () { expect(fn () => Json::outputByContains('', []))->toThrow(DocumentException::class); }); }); describe('::outputByJsonPath()', function () { test('throws an exception', function () { expect(fn () => Json::outputByJsonPath('', ''))->toThrow(DocumentException::class); }); }); describe('::outputFirstByFields()', function () { test('outputs a matching document', function () { $this->clearBuffer(); Json::outputFirstByFields(ThrowawayDb::TABLE, [Field::equal('value', 'another')]); expect($this->getBufferContents())->toBe(TWO); }); test('outputs one of several matching documents', function () { $this->clearBuffer(); Json::outputFirstByFields(ThrowawayDb::TABLE, [Field::equal('sub.foo', 'green')]); $doc = $this->getBufferContents(); expect($doc == TWO || $doc == FOUR)->toBeTrue("Document should have been two or four (actual $doc)"); }); test('outputs first of ordered matching documents', function () { $this->clearBuffer(); Json::outputFirstByFields(ThrowawayDb::TABLE, [Field::equal('sub.foo', 'green')], orderBy: [Field::named('n:num_value DESC')]); expect($this->getBufferContents())->toBe(FOUR); }); test('outputs "{}" when no documents match', function () { $this->clearBuffer(); Json::outputFirstByFields(ThrowawayDb::TABLE, [Field::equal('value', 'absent')]); expect($this->getBufferContents())->toBe('{}'); }); }); describe('::outputFirstByContains()', function () { test('throws an exception', function () { expect(fn () => Json::outputFirstByContains('', []))->toThrow(DocumentException::class); }); }); describe('::outputFirstByJsonPath()', function () { test('throws an exception', function () { expect(fn () => Json::outputFirstByJsonPath('', ''))->toThrow(DocumentException::class); }); });