PHP Classes

File: tests/Unit/Export/DbmlGeneratorTest.php

Recommend this page to a friend!
  Packages of Alberto Arena   Laravel Truss   tests/Unit/Export/DbmlGeneratorTest.php   Download  
File: tests/Unit/Export/DbmlGeneratorTest.php
Role: Example script
Content type: text/plain
Description: Example script
Class: Laravel Truss
View a diagram of a Laravel application models
Author: By
Last change:
Date: 6 days ago
Size: 4,704 bytes
 

Contents

Class file image Download
<?php

declare(strict_types=1);

use
AlbertoArena\Truss\Export\DbmlGenerator;
use
AlbertoArena\Truss\Tests\Support\SchemaBuilder;

/**
 * PHP port of the browser DBML serializer (resources/js/dbml-export.js). These
 * cases mirror tests/js/dbml-export.test.js so the two implementations stay in
 * step; the byte-for-byte guarantee is pinned separately by the cross-check test.
 */
function dbml(array $tables): string
{
    return (new
DbmlGenerator)->generate($tables);
}

it('emits a Table block with a single-column [pk]', function () {
   
$tables = SchemaBuilder::make()->table('users', function ($t) {
       
$t->id();
       
$t->string('name');
    })->
build()['tables'];

   
$out = dbml($tables);

   
expect($out)->toContain('Table users {')
        ->
and($out)->toMatch('/id "bigint unsigned" \[pk\]/');
});

it('quotes types with spaces but leaves simple types bare', function () {
   
$tables = SchemaBuilder::make()->table('users', function ($t) {
       
$t->id();
       
$t->string('name');
    })->
build()['tables'];

   
$out = dbml($tables);

   
expect($out)->toContain('"bigint unsigned"')
        ->
and($out)->toMatch('/name varchar\(255\)(?!")/');
});

it('renders a composite PK as an indexes block', function () {
   
$tables = SchemaBuilder::make()->table('role_user', function ($t) {
       
$t->column('role_id', 'bigint unsigned');
       
$t->column('user_id', 'bigint unsigned');
       
$t->primary(['role_id', 'user_id']);
    })->
build()['tables'];

   
$out = dbml($tables);

   
expect($out)->toContain('indexes {')
        ->
and($out)->toContain('(role_id, user_id) [pk]');
});

it('marks non-nullable non-key columns [not null] and leaves nullable ones bare', function () {
   
$tables = SchemaBuilder::make()->table('t', function ($t) {
       
$t->column('a', 'int', nullable: false);
       
$t->column('b', 'int', nullable: true);
    })->
build()['tables'];

   
$out = dbml($tables);

   
expect($out)->toMatch('/a int \[not null\]/')
        ->
and($out)->toMatch('/b int(?!\s*\[)/');
});

it('renders a default setting for numbers, keywords, expressions and strings', function () {
   
$tables = SchemaBuilder::make()->table('t', function ($t) {
       
$t->column('n', 'int', nullable: false, default: '0');
       
$t->column('flag', 'boolean', nullable: false, default: 'true');
       
$t->column('created', 'timestamp', nullable: false, default: 'CURRENT_TIMESTAMP');
       
$t->column('label', 'varchar(255)', nullable: false, default: "o'clock");
    })->
build()['tables'];

   
$out = dbml($tables);

   
expect($out)->toContain('default: 0')
        ->
and($out)->toContain('default: true')
        ->
and($out)->toContain('default: `CURRENT_TIMESTAMP`')
        ->
and($out)->toContain("default: 'o\\'clock'");
});

it('emits a Ref per foreign key with the correct direction', function () {
   
$tables = SchemaBuilder::make()
        ->
table('users', fn ($t) => $t->id())
        ->
table('posts', function ($t) {
           
$t->id();
           
$t->foreignId('user_id')->on('users');
        })->
build()['tables'];

   
expect(dbml($tables))->toContain('Ref: posts.user_id > users.id');
});

it('renders a composite foreign key with parenthesised columns', function () {
   
$tables = SchemaBuilder::make()
        ->
table('x', function ($t) {
           
$t->column('a', 'int');
           
$t->column('b', 'int');
           
$t->foreign('a', 'y', 'c');
        })
        ->
table('y', function ($t) {
           
$t->column('c', 'int');
           
$t->column('d', 'int');
           
$t->primary(['c', 'd']);
        })->
build()['tables'];

   
// Rewrite the single-column FK the helper produced into a composite one.
   
$tables[0]['foreign_keys'] = [[
       
'name' => 'fk',
       
'columns' => ['a', 'b'],
       
'references_table' => 'y',
       
'references_columns' => ['c', 'd'],
       
'on_update' => null,
       
'on_delete' => null,
    ]];

   
expect(dbml($tables))->toContain('Ref: x.(a, b) > y.(c, d)');
});

it('drops a Ref when the referenced table is absent from the export set', function () {
   
$tables = SchemaBuilder::make()->table('posts', function ($t) {
       
$t->id();
       
$t->foreignId('user_id')->on('users');
    })->
build()['tables'];

   
expect(dbml($tables))->not->toContain('Ref:');
});

it('keeps an enum as a quoted type with no Enum block', function () {
   
$tables = SchemaBuilder::make()->table('posts', function ($t) {
       
$t->id();
       
$t->column('status', "enum('draft','published','archived')");
    })->
build()['tables'];

   
$out = dbml($tables);

   
expect($out)->toContain('"enum(\'draft\',\'published\',\'archived\')"')
        ->
and($out)->not->toContain('Enum ');
});