<?php
namespace Tlf;
/**
* Facilitates storing SQL on-disk in sql files and converting those sql files to an array of commands & then serializing that.
*
* This is idealy a build tool, not a runtime tool, so you will `unserialize(file_get_contents(...))` to load the array of queries
*
* Or `@query(some.name, delimiter)` if you don't want to stop on a semi-colon
*
* @tagline Name queries in sql files with `@query(some.name)` and serialize them into a keyed array for later user
*
*/
class LilSql {
/**
* array of queries to use/serialize (you should serialize them & skip this processing in production!)
*/
public $queries = [];
/**
* Load sql files from the following dir into the queries
* @param $dir a directory path
*/
public function load_files(string $dir, string $namespace_prefix=''){
foreach (scandir($dir) as $f){
if (is_dir($dir.'/'.$f))continue;
if (substr($f,-4)!='.sql')continue;
$prefix = $namespace_prefix.substr($f,0,-3);
$file = file_get_contents($dir.'/'.$f);
$this->parse_sql($file, $prefix, $this->queries);
}
return $this->queries;
}
public function serialize(string $file){
file_put_contents($file, serialize($this->queries));
}
/**
* Convert an SQL string containing multiple queries into an array. All queries must have an explicit identifier.
*
* @see(\Tlf\LilDb\Test\Sql::testParseString()) for an example
*
* @param $sql sql containing multiple queries and an `@query(name, delimiter)` identifier
* @param $prefix prefix for the query name
* @param &$queries queries array to modify
*/
public function parse_sql(string $sql, string $prefix='', &$queries = []){
$pos = -1;
while(($pos = strpos($sql, '@query(', $pos+1))!==false){
$delimiter = ';';
$line_start = strrpos(substr($sql,0,$pos), "\n");
// var_dump($line_start);
// var_dump($pos);
$begin_of_command = strpos($sql, "(", $pos);
$end_of_command = strpos($sql, ")", $begin_of_command);
$next_line = strpos($sql, "\n", $end_of_command)+1;
$comma = strpos($sql, ',', $begin_of_command);
if ($comma === false || $comma > $end_of_command){
$name_stop = $end_of_command - $begin_of_command;
} else {
$name_stop = $comma - $begin_of_command;
$delimiter = trim(substr($sql, $comma+1, $end_of_command - $comma-1));
}
// $name_stop = $comma === false || $comma > $end_of_command ? $end_of_command - $begin_of_command :
// var_dump($begin_of_command);
// var_dump($end_of_command);
// var_dump($comma);
// var_dump($name_stop);
$name = trim(substr($sql, $begin_of_command+1, $name_stop-1));
// exit;
// var_dump($name);
// var_dump($delimiter);
$sql_end = strpos($sql, $delimiter, $end_of_command);
// make the sql block start at the next line after the @query() tag
$sql_block = trim(substr($sql, $next_line, $sql_end-$next_line+strlen($delimiter)));
// // make the sql block include the @query() tag that defines it
// $sql_block = trim(substr($sql, $line_start, $sql_end-$line_start+strlen($delimiter)));
// var_dump($sql_end);
// var_dump($sql_block);
// // $sql =
// exit;
if (isset($queries[$prefix.$name])){
throw new \Exception("There is already a query with name '$name'");
}
$queries[$prefix.$name] = $sql_block;
}
return $queries;
}
}