Skip to content

Commit 778a082

Browse files
committed
feat: add functions
1 parent 85c752b commit 778a082

16 files changed

+691
-74
lines changed

README.md

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,82 @@ class RecentOrdersView extends View
222222

223223
<!-- #### 💿 Materialized View -->
224224
<!---->
225-
<!-- #### 🛠 Function -->
226-
<!---->
225+
#### 📐 Function
226+
227+
The `Function_` class is used to create functions in the database.
228+
229+
> [!TIP]
230+
> The class is named `Function_` as `function` is a reserved keyword in PHP.
231+
232+
In addition to the options above, you can use the following options to further customize the function:
233+
234+
```php
235+
<?php
236+
237+
namespace Database\Entities\Functions;
238+
239+
use CalebDW\SqlEntities\Function_;
240+
241+
class Add extends Function_
242+
{
243+
/** If the function aggregates. */
244+
protected bool $aggregate = false;
245+
246+
protected array $arguments = [
247+
'integer',
248+
'integer',
249+
];
250+
251+
/** The language the function is written in. */
252+
protected string $language = 'SQL';
253+
254+
protected array $characteristics = [];
255+
256+
/** The function return type. */
257+
protected string $returns = 'integer';
258+
259+
#[Override]
260+
public function definition(): string
261+
{
262+
return <<<'SQL'
263+
RETURN $1 + $2;
264+
SQL;
265+
}
266+
}
267+
```
268+
269+
Loadable functions are also supported:
270+
271+
```php
272+
<?php
273+
274+
namespace Database\Entities\Functions;
275+
276+
use CalebDW\SqlEntities\Function_;
277+
278+
class Add extends Function_
279+
{
280+
protected array $arguments = [
281+
'integer',
282+
'integer',
283+
];
284+
285+
/** The language the function is written in. */
286+
protected string $language = 'c';
287+
288+
protected bool $loadable = true;
289+
290+
/** The function return type. */
291+
protected string $returns = 'integer';
292+
293+
#[Override]
294+
public function definition(): string
295+
{
296+
return 'c_add';
297+
}
298+
}
299+
```
300+
227301
<!-- #### 📤 Procedure -->
228302
<!---->
229303
<!-- #### ⚡ Trigger -->

src/Function_.php

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace CalebDW\SqlEntities;
6+
7+
use CalebDW\SqlEntities\Concerns\DefaultSqlEntityBehaviour;
8+
use CalebDW\SqlEntities\Contracts\SqlEntity;
9+
10+
abstract class Function_ implements SqlEntity
11+
{
12+
use DefaultSqlEntityBehaviour;
13+
14+
/** If the function aggregates. */
15+
protected bool $aggregate = false;
16+
17+
/**
18+
* The function arguments.
19+
*
20+
* @var list<string>
21+
*/
22+
protected array $arguments = [];
23+
24+
/** The language the function is written in. */
25+
protected string $language = 'SQL';
26+
27+
/** If the function is loadable. */
28+
protected bool $loadable = false;
29+
30+
/**
31+
* The function characteristics.
32+
*
33+
* @var list<string>
34+
*/
35+
protected array $characteristics = [];
36+
37+
/** The function return type. */
38+
protected string $returns = '';
39+
40+
/** The language the function is written in. */
41+
public function aggregate(): bool
42+
{
43+
return $this->aggregate;
44+
}
45+
46+
/**
47+
* The function arguments.
48+
*
49+
* @return list<string>
50+
*/
51+
public function arguments(): array
52+
{
53+
return $this->arguments;
54+
}
55+
56+
/**
57+
* The function characteristics.
58+
*
59+
* @return list<string>
60+
*/
61+
public function characteristics(): array
62+
{
63+
return $this->characteristics;
64+
}
65+
66+
/** The language the function is written in. */
67+
public function language(): string
68+
{
69+
return $this->language;
70+
}
71+
72+
/** If the function is loadable. */
73+
public function loadable(): bool
74+
{
75+
return $this->loadable;
76+
}
77+
78+
/** The function return type. */
79+
public function returns(): string
80+
{
81+
return $this->returns;
82+
}
83+
}

src/Grammars/Grammar.php

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace CalebDW\SqlEntities\Grammars;
66

77
use CalebDW\SqlEntities\Contracts\SqlEntity;
8+
use CalebDW\SqlEntities\Function_;
89
use CalebDW\SqlEntities\View;
910
use Illuminate\Database\Connection;
1011
use Illuminate\Support\Str;
@@ -17,10 +18,12 @@ public function __construct(
1718
) {
1819
}
1920

21+
/** Compile the SQL statement to create the entity. */
2022
public function compileCreate(SqlEntity $entity): string
2123
{
2224
$statement = match (true) {
23-
$entity instanceof View => $this->compileViewCreate($entity),
25+
$entity instanceof Function_ => $this->compileFunctionCreate($entity),
26+
$entity instanceof View => $this->compileViewCreate($entity),
2427

2528
default => throw new InvalidArgumentException(
2629
sprintf('Unsupported entity [%s].', $entity::class),
@@ -30,10 +33,12 @@ public function compileCreate(SqlEntity $entity): string
3033
return $this->clean($statement);
3134
}
3235

36+
/** Compile the SQL statement to drop the entity. */
3337
public function compileDrop(SqlEntity $entity): string
3438
{
3539
$statement = match (true) {
36-
$entity instanceof View => $this->compileViewDrop($entity),
40+
$entity instanceof Function_ => $this->compileFunctionDrop($entity),
41+
$entity instanceof View => $this->compileViewDrop($entity),
3742

3843
default => throw new InvalidArgumentException(
3944
sprintf('Unsupported entity [%s].', $entity::class),
@@ -47,10 +52,21 @@ public function compileDrop(SqlEntity $entity): string
4752
public function supportsEntity(SqlEntity $entity): bool
4853
{
4954
return match (true) {
50-
$entity instanceof View => true,
51-
default => false,
55+
$entity instanceof Function_ => true,
56+
$entity instanceof View => true,
57+
default => false,
5258
};
5359
}
60+
61+
abstract protected function compileFunctionCreate(Function_ $entity): string;
62+
63+
protected function compileFunctionDrop(Function_ $entity): string
64+
{
65+
return <<<SQL
66+
DROP FUNCTION IF EXISTS {$entity->name()}
67+
SQL;
68+
}
69+
5470
abstract protected function compileViewCreate(View $entity): string;
5571

5672
protected function compileViewDrop(View $entity): string
@@ -88,7 +104,12 @@ protected function compileCheckOption(string|true|null $option): string
88104
protected function clean(string $value): string
89105
{
90106
return Str::of($value)
91-
->replaceMatches('/ +/', ' ')
107+
// remove extra spaces in between words
108+
->replaceMatches('/(?<=\S) {2,}(?=\S)/', ' ')
109+
// remove trailing spaces at end of line
110+
->replaceMatches('/ +\n/', "\n")
111+
// remove duplicate new lines
112+
->replaceMatches('/\n{2,}/', "\n")
92113
->trim()
93114
->value();
94115
}

src/Grammars/MariaDbGrammar.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,33 @@
44

55
namespace CalebDW\SqlEntities\Grammars;
66

7+
use CalebDW\SqlEntities\Function_;
78
use CalebDW\SqlEntities\View;
89
use Override;
910

1011
class MariaDbGrammar extends Grammar
1112
{
13+
#[Override]
14+
protected function compileFunctionCreate(Function_ $entity): string
15+
{
16+
$arguments = $this->compileList($entity->arguments());
17+
$aggregate = $entity->aggregate() ? 'AGGREGATE' : '';
18+
$characteristics = implode("\n", $entity->characteristics());
19+
$definition = $entity->toString();
20+
21+
if ($entity->loadable()) {
22+
$arguments = '';
23+
$definition = "SONAME {$definition}";
24+
}
25+
26+
return <<<SQL
27+
CREATE OR REPLACE {$aggregate} FUNCTION {$entity->name()}{$arguments}
28+
RETURNS {$entity->returns()}
29+
{$characteristics}
30+
{$definition}
31+
SQL;
32+
}
33+
1234
#[Override]
1335
protected function compileViewCreate(View $entity): string
1436
{

src/Grammars/MySqlGrammar.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,34 @@
44

55
namespace CalebDW\SqlEntities\Grammars;
66

7+
use CalebDW\SqlEntities\Function_;
78
use CalebDW\SqlEntities\View;
89
use Override;
910

1011
class MySqlGrammar extends Grammar
1112
{
13+
#[Override]
14+
protected function compileFunctionCreate(Function_ $entity): string
15+
{
16+
$arguments = $this->compileList($entity->arguments());
17+
$aggregate = '';
18+
$definition = $entity->toString();
19+
$characteristics = implode("\n", $entity->characteristics());
20+
21+
if ($entity->loadable()) {
22+
$aggregate = $entity->aggregate() ? 'AGGREGATE' : '';
23+
$arguments = '';
24+
$definition = "SONAME {$definition}";
25+
}
26+
27+
return <<<SQL
28+
CREATE {$aggregate} FUNCTION IF NOT EXISTS {$entity->name()}{$arguments}
29+
RETURNS {$entity->returns()}
30+
{$characteristics}
31+
{$definition}
32+
SQL;
33+
}
34+
1235
#[Override]
1336
protected function compileViewCreate(View $entity): string
1437
{

src/Grammars/PostgresGrammar.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,45 @@
44

55
namespace CalebDW\SqlEntities\Grammars;
66

7+
use CalebDW\SqlEntities\Function_;
78
use CalebDW\SqlEntities\View;
89
use Override;
910

1011
class PostgresGrammar extends Grammar
1112
{
13+
#[Override]
14+
protected function compileFunctionCreate(Function_ $entity): string
15+
{
16+
$arguments = $this->compileList($entity->arguments());
17+
$language = $entity->language();
18+
$definition = $entity->toString();
19+
$characteristics = implode("\n", $entity->characteristics());
20+
21+
$definition = match (true) {
22+
$entity->loadable() => "AS {$definition}",
23+
strtolower($language) !== 'sql' => "AS \$function$\n{$definition}\n\$function$",
24+
default => $definition,
25+
};
26+
27+
return <<<SQL
28+
CREATE OR REPLACE FUNCTION {$entity->name()}{$arguments}
29+
RETURNS {$entity->returns()}
30+
LANGUAGE {$language}
31+
{$characteristics}
32+
{$definition}
33+
SQL;
34+
}
35+
36+
#[Override]
37+
protected function compileFunctionDrop(Function_ $entity): string
38+
{
39+
$arguments = $this->compileList($entity->arguments());
40+
41+
return <<<SQL
42+
DROP FUNCTION IF EXISTS {$entity->name()}{$arguments}
43+
SQL;
44+
}
45+
1246
#[Override]
1347
protected function compileViewCreate(View $entity): string
1448
{

src/Grammars/SQLiteGrammar.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,30 @@
44

55
namespace CalebDW\SqlEntities\Grammars;
66

7+
use CalebDW\SqlEntities\Contracts\SqlEntity;
8+
use CalebDW\SqlEntities\Function_;
79
use CalebDW\SqlEntities\View;
810
use Override;
11+
use RuntimeException;
912

1013
class SQLiteGrammar extends Grammar
1114
{
15+
#[Override]
16+
public function supportsEntity(SqlEntity $entity): bool
17+
{
18+
return match (true) {
19+
$entity instanceof Function_ => false,
20+
21+
default => parent::supportsEntity($entity),
22+
};
23+
}
24+
25+
#[Override]
26+
protected function compileFunctionCreate(Function_ $entity): string
27+
{
28+
throw new RuntimeException('SQLite does not support user-defined functions.');
29+
}
30+
1231
#[Override]
1332
protected function compileViewCreate(View $entity): string
1433
{

0 commit comments

Comments
 (0)