Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert table_schema type to TableSchema object #100

Merged
merged 2 commits into from
May 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 91 additions & 39 deletions src/BuildSchemaCLI.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,17 @@
use namespace HH\Lib\{C, Regex};
use type Facebook\CLILib\CLIWithArguments;
use namespace Facebook\CLILib\CLIOptions;
use type Facebook\HackCodegen\{HackBuilderKeys, HackBuilderValues, HackCodegenConfig, HackCodegenFactory};

final class BuildSchemaCLI extends CLIWithArguments {
private string $constName = 'DB_SCHEMA';
private string $functionName = 'get_db_schema';

<<__Override>>
protected function getSupportedOptions(): vec<CLIOptions\CLIOption> {
return vec[CLIOptions\with_required_string(
$name ==> {
$this->constName = $name;
$this->functionName = $name;
},
'The name of the constant to generate. Defaults to DB_SCHEMA',
'The name of the function name to generate. Defaults to get_db_schema',
'--name',
)];
}
Expand Down Expand Up @@ -67,43 +66,96 @@ protected function getSupportedOptions(): vec<CLIOptions\CLIOption> {
$generated[$db] = $schema;
}

$cg = new HackCodegenFactory(new HackCodegenConfig());

$generated = $cg->codegenConstant($this->constName)
->setType('dict<string, dict<string, table_schema>>')
->setValue($generated, HackBuilderValues::dict(HackBuilderKeys::export(), HackBuilderValues::dict(
HackBuilderKeys::export(),
// special exporters are required to make shapes and enum values, ::export would turn them into arrays and strings
HackBuilderValues::shapeWithPerKeyRendering(
shape(
'name' => HackBuilderValues::export(),
'indexes' =>
HackBuilderValues::vec(HackBuilderValues::shapeWithUniformRendering(HackBuilderValues::export())),
'fields' => HackBuilderValues::vec(HackBuilderValues::shapeWithPerKeyRendering(
shape(
'name' => HackBuilderValues::export(),
'type' => HackBuilderValues::lambda(($_cfg, $str) ==> 'DataType::'.$str),
'length' => HackBuilderValues::export(),
'null' => HackBuilderValues::export(),
'hack_type' => HackBuilderValues::export(),
'default' => HackBuilderValues::export(),
'unsigned' => HackBuilderValues::export(),
),
)),
),
),
)))
->render();

$generated = <<<EOT
use type Slack\\SQLFake\\{table_schema, DataType};


EOT
.
$generated;
$generated = self::getRenderedHackTableSchemaWithClusters($this->functionName, $generated);

await $terminal->getStdout()->writeAllAsync($generated);
return 0;
}

//
// Write out a top level import target containing all of our generated db files.
//
// This also contains a memoized function that returns a lookup for each field in our DB tables and the type of those fields.
//

public static function getRenderedHackTableSchemaWithClusters(
string $function_name,
dict<string, dict<string, TableSchema>> $table_schemas,
): string {
$file_contents = '';

$file_contents .= "use type Slack\\SQLFake\\{Column, DataType, Index, TableSchema};\n";
$file_contents .= "\n";
$file_contents .= "<<__Memoize>>\n";
$file_contents .= "function {$function_name}(): dict<string, dict<string, table_schema>> {\n";
$file_contents .= "\treturn dict[\n";
foreach ($table_schemas as $cluster => $tables) {
$file_contents .= "\t\t'{$cluster}' => ".self::getRenderedHackTableSchema($tables, "\t\t");
}
$file_contents .= "\t];\n";
$file_contents .= "}\n";

return $file_contents;
}

public static function getRenderedHackTableSchema(
dict<string, TableSchema> $table_schemas,
string $indentation,
): string {
$file_contents = "dict[\n";
foreach ($table_schemas as $table_schema) {
$table_name = $table_schema->name;
$file_contents .= $indentation."\t'{$table_name}' => new TableSchema(\n";

//
// Write out the fields
//

$file_contents .= $indentation."\t\t'{$table_name}',\n";
$file_contents .= $indentation."\t\tvec[\n";
foreach ($table_schema->fields as $field) {
$file_contents .= $indentation."\t\t\tnew Column(\n";
$file_contents .= $indentation."\t\t\t\t'{$field->name}',\n";
$file_contents .= $indentation."\t\t\t\tDataType::{$field->type},\n";
$file_contents .= $indentation."\t\t\t\t{$field->length},\n";
$file_contents .= $indentation."\t\t\t\t" . ($field->null ? 'true' : 'false') . ",\n";
$file_contents .= $indentation."\t\t\t\t'{$field->hack_type}',\n";
if ($field->unsigned is nonnull || $field->default is nonnull) {
if ($field->unsigned is nonnull) {
$file_contents .= $indentation."\t\t\t\t" . ($field->unsigned ? 'true' : 'false') . ",\n";
} else {
$file_contents .= $indentation."\t\t\t\tnull,\n";
}
if ($field->default is nonnull) {
$file_contents .= $indentation."\t\t\t\t'{$field->default}',\n";
}
}
$file_contents .= $indentation."\t\t\t),\n";
}
$file_contents .= $indentation."\t\t],\n";

//
// Write out the indexes
//

$file_contents .= $indentation."\t\tvec[\n";
foreach ($table_schema->indexes as $index) {
$file_contents .= $indentation."\t\t\tnew Index(\n";
$file_contents .= $indentation."\t\t\t\t'{$index->name}',\n";
$file_contents .= $indentation."\t\t\t\t'{$index->type}',\n";
$fields = 'keyset[\''.\implode('\', \'', $index->fields).'\']';
$file_contents .= $indentation."\t\t\t\t{$fields},\n";
$file_contents .= $indentation."\t\t\t),\n";
}
$file_contents .= $indentation."\t\t],\n";
$file_contents .= $indentation."\t),\n";
}

$file_contents .= $indentation."],\n";
return $file_contents;
}

private static function varExportStringArray(Container<string> $array): string {
return C\is_empty($array) ? 'vec[]' : 'vec[\''.\HH\Lib\Str\join($array, '\', \'').'\']';
}
}
13 changes: 13 additions & 0 deletions src/Column.hack
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Slack\SQLFake;

final class Column {
public function __construct(
public string $name,
public DataType $type,
public int $length,
public bool $null,
public string $hack_type,
public ?bool $unsigned = null,
public ?string $default = null,
) {}
}
Loading
Loading