|
5 | 5 | use namespace HH\Lib\{C, Regex}; |
6 | 6 | use type Facebook\CLILib\CLIWithArguments; |
7 | 7 | use namespace Facebook\CLILib\CLIOptions; |
8 | | -use type Facebook\HackCodegen\{HackBuilderKeys, HackBuilderValues, HackCodegenConfig, HackCodegenFactory}; |
9 | 8 |
|
10 | 9 | final class BuildSchemaCLI extends CLIWithArguments { |
11 | | - private string $constName = 'DB_SCHEMA'; |
| 10 | + private string $functionName = 'get_db_schema'; |
12 | 11 |
|
13 | 12 | <<__Override>> |
14 | 13 | protected function getSupportedOptions(): vec<CLIOptions\CLIOption> { |
15 | 14 | return vec[CLIOptions\with_required_string( |
16 | 15 | $name ==> { |
17 | | - $this->constName = $name; |
| 16 | + $this->functionName = $name; |
18 | 17 | }, |
19 | | - 'The name of the constant to generate. Defaults to DB_SCHEMA', |
| 18 | + 'The name of the function name to generate. Defaults to get_db_schema', |
20 | 19 | '--name', |
21 | 20 | )]; |
22 | 21 | } |
@@ -67,43 +66,96 @@ protected function getSupportedOptions(): vec<CLIOptions\CLIOption> { |
67 | 66 | $generated[$db] = $schema; |
68 | 67 | } |
69 | 68 |
|
70 | | - $cg = new HackCodegenFactory(new HackCodegenConfig()); |
71 | | - |
72 | | - $generated = $cg->codegenConstant($this->constName) |
73 | | - ->setType('dict<string, dict<string, table_schema>>') |
74 | | - ->setValue($generated, HackBuilderValues::dict(HackBuilderKeys::export(), HackBuilderValues::dict( |
75 | | - HackBuilderKeys::export(), |
76 | | - // special exporters are required to make shapes and enum values, ::export would turn them into arrays and strings |
77 | | - HackBuilderValues::shapeWithPerKeyRendering( |
78 | | - shape( |
79 | | - 'name' => HackBuilderValues::export(), |
80 | | - 'indexes' => |
81 | | - HackBuilderValues::vec(HackBuilderValues::shapeWithUniformRendering(HackBuilderValues::export())), |
82 | | - 'fields' => HackBuilderValues::vec(HackBuilderValues::shapeWithPerKeyRendering( |
83 | | - shape( |
84 | | - 'name' => HackBuilderValues::export(), |
85 | | - 'type' => HackBuilderValues::lambda(($_cfg, $str) ==> 'DataType::'.$str), |
86 | | - 'length' => HackBuilderValues::export(), |
87 | | - 'null' => HackBuilderValues::export(), |
88 | | - 'hack_type' => HackBuilderValues::export(), |
89 | | - 'default' => HackBuilderValues::export(), |
90 | | - 'unsigned' => HackBuilderValues::export(), |
91 | | - ), |
92 | | - )), |
93 | | - ), |
94 | | - ), |
95 | | - ))) |
96 | | - ->render(); |
97 | | - |
98 | | - $generated = <<<EOT |
99 | | -use type Slack\\SQLFake\\{table_schema, DataType}; |
100 | | -
|
101 | | -
|
102 | | -EOT |
103 | | - . |
104 | | - $generated; |
| 69 | + $generated = self::getRenderedHackTableSchemaWithClusters($this->functionName, $generated); |
105 | 70 |
|
106 | 71 | await $terminal->getStdout()->writeAllAsync($generated); |
107 | 72 | return 0; |
108 | 73 | } |
| 74 | + |
| 75 | + // |
| 76 | + // Write out a top level import target containing all of our generated db files. |
| 77 | + // |
| 78 | + // This also contains a memoized function that returns a lookup for each field in our DB tables and the type of those fields. |
| 79 | + // |
| 80 | + |
| 81 | + public static function getRenderedHackTableSchemaWithClusters( |
| 82 | + string $function_name, |
| 83 | + dict<string, dict<string, TableSchema>> $table_schemas, |
| 84 | + ): string { |
| 85 | + $file_contents = ''; |
| 86 | + |
| 87 | + $file_contents .= "use type Slack\\SQLFake\\{Column, DataType, Index, TableSchema};\n"; |
| 88 | + $file_contents .= "\n"; |
| 89 | + $file_contents .= "<<__Memoize>>\n"; |
| 90 | + $file_contents .= "function {$function_name}(): dict<string, dict<string, table_schema>> {\n"; |
| 91 | + $file_contents .= "\treturn dict[\n"; |
| 92 | + foreach ($table_schemas as $cluster => $tables) { |
| 93 | + $file_contents .= "\t\t'{$cluster}' => ".self::getRenderedHackTableSchema($tables, "\t\t"); |
| 94 | + } |
| 95 | + $file_contents .= "\t];\n"; |
| 96 | + $file_contents .= "}\n"; |
| 97 | + |
| 98 | + return $file_contents; |
| 99 | + } |
| 100 | + |
| 101 | + public static function getRenderedHackTableSchema( |
| 102 | + dict<string, TableSchema> $table_schemas, |
| 103 | + string $indentation, |
| 104 | + ): string { |
| 105 | + $file_contents = "dict[\n"; |
| 106 | + foreach ($table_schemas as $table_schema) { |
| 107 | + $table_name = $table_schema->name; |
| 108 | + $file_contents .= $indentation."\t'{$table_name}' => new TableSchema(\n"; |
| 109 | + |
| 110 | + // |
| 111 | + // Write out the fields |
| 112 | + // |
| 113 | + |
| 114 | + $file_contents .= $indentation."\t\t'{$table_name}',\n"; |
| 115 | + $file_contents .= $indentation."\t\tvec[\n"; |
| 116 | + foreach ($table_schema->fields as $field) { |
| 117 | + $file_contents .= $indentation."\t\t\tnew Column(\n"; |
| 118 | + $file_contents .= $indentation."\t\t\t\t'{$field->name}',\n"; |
| 119 | + $file_contents .= $indentation."\t\t\t\tDataType::{$field->type},\n"; |
| 120 | + $file_contents .= $indentation."\t\t\t\t{$field->length},\n"; |
| 121 | + $file_contents .= $indentation."\t\t\t\t" . ($field->null ? 'true' : 'false') . ",\n"; |
| 122 | + $file_contents .= $indentation."\t\t\t\t'{$field->hack_type}',\n"; |
| 123 | + if ($field->unsigned is nonnull || $field->default is nonnull) { |
| 124 | + if ($field->unsigned is nonnull) { |
| 125 | + $file_contents .= $indentation."\t\t\t\t" . ($field->unsigned ? 'true' : 'false') . ",\n"; |
| 126 | + } else { |
| 127 | + $file_contents .= $indentation."\t\t\t\tnull,\n"; |
| 128 | + } |
| 129 | + if ($field->default is nonnull) { |
| 130 | + $file_contents .= $indentation."\t\t\t\t'{$field->default}',\n"; |
| 131 | + } |
| 132 | + } |
| 133 | + $file_contents .= $indentation."\t\t\t),\n"; |
| 134 | + } |
| 135 | + $file_contents .= $indentation."\t\t],\n"; |
| 136 | + |
| 137 | + // |
| 138 | + // Write out the indexes |
| 139 | + // |
| 140 | + |
| 141 | + $file_contents .= $indentation."\t\tvec[\n"; |
| 142 | + foreach ($table_schema->indexes as $index) { |
| 143 | + $file_contents .= $indentation."\t\t\tnew Index(\n"; |
| 144 | + $file_contents .= $indentation."\t\t\t\t'{$index->name}',\n"; |
| 145 | + $file_contents .= $indentation."\t\t\t\t'{$index->type}',\n"; |
| 146 | + $fields = 'keyset[\''.\implode('\', \'', $index->fields).'\']'; |
| 147 | + $file_contents .= $indentation."\t\t\t\t{$fields},\n"; |
| 148 | + $file_contents .= $indentation."\t\t\t),\n"; |
| 149 | + } |
| 150 | + $file_contents .= $indentation."\t\t],\n"; |
| 151 | + $file_contents .= $indentation."\t),\n"; |
| 152 | + } |
| 153 | + |
| 154 | + $file_contents .= $indentation."],\n"; |
| 155 | + return $file_contents; |
| 156 | + } |
| 157 | + |
| 158 | + private static function varExportStringArray(Container<string> $array): string { |
| 159 | + return C\is_empty($array) ? 'vec[]' : 'vec[\''.\HH\Lib\Str\join($array, '\', \'').'\']'; |
| 160 | + } |
109 | 161 | } |
0 commit comments