Skip to content

Commit

Permalink
Merge pull request #16 from vc-urvin/main
Browse files Browse the repository at this point in the history
Add validation for unique constraint  | update messages | add suggestion for varchar datatype
  • Loading branch information
ruchit288 authored Apr 27, 2023
2 parents 81edcc2 + 31f8915 commit eee1893
Show file tree
Hide file tree
Showing 11 changed files with 120 additions and 54 deletions.
27 changes: 18 additions & 9 deletions src/Commands/DBConstraintCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ public function selectedConstraint(string $selectConstrain, array $noConstraintF

$auditService = app(AuditService::class);

if ($selectConstrain === Constant::CONSTRAINT_FOREIGN_KEY || $selectConstrain === Constant::CONSTRAINT_UNIQUE_KEY) {
if ($selectConstrain === Constant::CONSTRAINT_FOREIGN_KEY) {
$tableHasValue = $auditService->tableHasValue($tableName);

if ($tableHasValue) {
Expand All @@ -213,15 +213,24 @@ public function selectedConstraint(string $selectConstrain, array $noConstraintF
$fields = $noConstraintFields['mix'];
}

$selectField = $this->choice(
__('Lang::messages.constraint.question.field_selection') . ' ' . strtolower($selectConstrain) . ' key',
$fields
);
if($selectConstrain === Constant::CONSTRAINT_UNIQUE_KEY) {
$fields = $auditService->getUniqueFields($tableName, $noConstraintFields['mix']);
if (empty($fields)) {
$this->errorMessage(__('Lang::messages.constraint.error_message.unique_constraint_not_apply'));
}
}

if ($selectConstrain === Constant::CONSTRAINT_FOREIGN_KEY) {
$this->foreignKeyConstraint($tableName, $selectField);
} else {
$auditService->addConstraint($tableName, $selectField, $selectConstrain);
if (!$this->skip) {
$selectField = $this->choice(
__('Lang::messages.constraint.question.field_selection') . ' ' . strtolower($selectConstrain) . ' key',
$fields
);

if ($selectConstrain === Constant::CONSTRAINT_FOREIGN_KEY) {
$this->foreignKeyConstraint($tableName, $selectField);
} else {
$auditService->addConstraint($tableName, $selectField, $selectConstrain);
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/Commands/DBStandardCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public function handle(): ?int
$continue = Constant::STATUS_TRUE;

do {
$tableName = $this->ask('Please enter table name if you want to see the table report');
$tableName = $this->anticipate('Please enter table name if you want to see the table report', $ruleService->getTableList());

if (empty($tableName)) {
return render(view('DBAuditor::error_message', ['message' => 'No Table Found']));
Expand Down
1 change: 1 addition & 0 deletions src/Constants/Constant.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class Constant

// Datatype List
public const DATATYPE_VARCHAR = 'varchar';
public const DATATYPE_VARCHAR_SIZE = '255';
public const DATATYPE_STRING = 'string';
public const DATATYPE_INT = 'int';
public const DATATYPE_INTEGER = 'integer';
Expand Down
2 changes: 1 addition & 1 deletion src/Database/migrations/update_table_index.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
public function up(): void
{
Schema::table($tableName, function (Blueprint $table) {
$table->$dataType($fieldName)->change()->index();
$table->$dataType($fieldName, $length)->change()->index();
});
}

Expand Down
29 changes: 17 additions & 12 deletions src/Lang/en/messages.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,34 @@
'question' => [
'table_selection' => 'Which table would you like to audit?',
'continue' => 'Do you want add more constraint?',
'constraint_selection' => 'Please select a constraint which you want to add',
'field_selection' => 'Please select a field to add constraint',
'foreign_table' => 'Please add foreign table name',
'foreign_field' => 'Please add foreign table primary key name',
'constraint_selection' => 'Please select a constraint which you want to add.',
'field_selection' => 'Please select a field to add constraint.',
'foreign_table' => 'Please add foreign table name.',
'foreign_field' => 'Please add primary key name of foreign table.',
],
'success_message' => [
'constraint_added' => 'Congratulations! Constraint Added Successfully'
'constraint_added' => 'Congratulations! Constraint Added Successfully.'
],
'error_message' => [
'constraint_not_apply' => 'Can not apply :constraint key | Please truncate table',
'foreign_not_apply' => 'Columns must have the same data type',
'constraint_not_apply' => 'Can not apply :constraint key | Please truncate table.',
'foreign_not_apply' => 'Columns must have the same datatype.',
'table_not_found' => 'Foreign table not found.',
'field_not_found' => 'Foreign field not found.',
'foreign_selected_table_match' => "Can't add constraint because foreign :foreign table and selected :selected table match."
'foreign_selected_table_match' => "Can't add constraint because :selected table and foreign :foreign table are same. Please use different table name.",
'unique_constraint_not_apply' => "All field values are duplicate. You can't add unique constraint.",
]
],
'standard' => [
'error_message' => [
'length' => 'Table name should not be more than 64 characters',
'plural' => 'Table name should be plural',
'length' => 'Table name should not be more than 64 characters.',
'plural' => 'Table name should be plural.',
'space' => 'Space between words is not advised. Please Use Underscore "_"',
'alphabets' => 'Numbers are not for names and is not advised! Please use alphabets for name',
'lowercase' => 'Name should be lowercase'
'alphabets' => 'Numbers are not for names and is not advised! Please use alphabets for name.',
'lowercase' => 'Name should be in lowercase.',
'datatype_change' => 'Here you can use CHAR datatype instead of VARCHAR if data values in a column are of the same length.',
],
'question' => [
'table_selection' => 'Please enter table name if you want to see the table report',
]
]
];
51 changes: 32 additions & 19 deletions src/Services/AuditService.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,10 @@ public function getNoConstraintFields(string $tableName): array
if (!in_array($field->DATA_TYPE, Constant::RESTRICT_DATATYPE)) {
if (str_contains($field->DATA_TYPE, "int")) {
$fields['integer'][] = $field->COLUMN_NAME;
} else {
}
$fieldDetails = $this->dBConnectionService->getFieldDataType($tableName, $field->COLUMN_NAME);

if($fieldDetails['size'] <= Constant::DATATYPE_VARCHAR_SIZE) {
$fields['mix'][] = $field->COLUMN_NAME;
}
}
Expand All @@ -109,7 +112,10 @@ public function getConstraintList(string $tableName, array $fields): array
$constrainList = Constant::ARRAY_DECLARATION;

if (!empty($fields['integer'])) {
$constrainList[] = Constant::CONSTRAINT_FOREIGN_KEY;

if(!$this->tableHasValue($tableName)) {
$constrainList[] = Constant::CONSTRAINT_FOREIGN_KEY;
}

if (empty($this->getConstraintField($tableName, Constant::CONSTRAINT_PRIMARY_KEY))) {
$constrainList[] = Constant::CONSTRAINT_PRIMARY_KEY;
Expand All @@ -118,7 +124,10 @@ public function getConstraintList(string $tableName, array $fields): array

if (!empty($fields['mix'])) {
$constrainList[] = Constant::CONSTRAINT_INDEX_KEY;
$constrainList[] = Constant::CONSTRAINT_UNIQUE_KEY;

if(!empty($this->getUniqueFields($tableName, $fields['mix']))) {
$constrainList[] = Constant::CONSTRAINT_UNIQUE_KEY;
}
}
return $constrainList;
}
Expand Down Expand Up @@ -254,16 +263,16 @@ public function migrateConstrain(
string $referenceField = null, string $referenceTableName = null): bool
{
try {
$dataType = $this->getFieldDataType($tableName, $fieldName);
$fieldDetails = $this->dBConnectionService->getFieldDataType($tableName, $fieldName);
$fieldDataType = Constant::NULL;

if ($dataType) {
if ($dataType === Constant::DATATYPE_VARCHAR) {
if (!empty($fieldDetails['data_type'])) {
if ($fieldDetails['data_type'] === Constant::DATATYPE_VARCHAR) {
$fieldDataType = Constant::DATATYPE_STRING;
} elseif ($dataType === Constant::DATATYPE_INT) {
} elseif ($fieldDetails['data_type'] === Constant::DATATYPE_INT) {
$fieldDataType = Constant::DATATYPE_INTEGER;
} else {
$fieldDataType = $dataType;
$fieldDataType = $fieldDetails['data_type'];
}
}

Expand All @@ -272,7 +281,8 @@ public function migrateConstrain(
"fieldName" => $fieldName,
"referenceField" => $referenceField,
"referenceTable" => $referenceTableName,
"dataType" => $fieldDataType
"dataType" => $fieldDataType,
'length' => $fieldDetails['size'],
];

$contents = file_get_contents(__DIR__ . "/../Database/migrations/" . $fileName);
Expand All @@ -290,7 +300,6 @@ public function migrateConstrain(
File::put(database_path("/migrations/" . $time . "_update_" . $tableName . "_" . $fieldName . "_" . strtolower($constrainName) . ".php"), $contents);

Artisan::call("migrate", [
'--force' => true,
'--path' => "database/migrations/" . $time . "_update_" . $tableName . "_" . $fieldName . "_" . strtolower($constrainName) . ".php"
]);
} catch (Exception $exception) {
Expand All @@ -300,23 +309,27 @@ public function migrateConstrain(
}

/**
* Get Field Data Type
* Get Unique Fields
* @param string $tableName
* @param string $fieldName
* @return mixed
* @param array $fields
* @return array
*/
public function getFieldDataType(string $tableName, string $fieldName): mixed
public function getUniqueFields(string $tableName, array $fields): array
{
$uniqueField = Constant::ARRAY_DECLARATION;
try {
$dataType = DB::select("SELECT `DATA_TYPE` FROM `INFORMATION_SCHEMA`.`COLUMNS`
WHERE `TABLE_SCHEMA`= '" . env('DB_DATABASE') . "' AND `TABLE_NAME`= '" . $tableName . "' AND `COLUMN_NAME` = '" . $fieldName . "' ");
foreach ($fields as $field) {
$query = "SELECT `". $field ."`, COUNT(`". $field ."`) as count FROM ".$tableName." GROUP BY `".$field."` HAVING COUNT(`".$field."`) > 1";
$result = DB::select($query);

if (isset($dataType[0]->DATA_TYPE) && $dataType[0]->DATA_TYPE !== null) {
return $dataType[0]->DATA_TYPE;
if (empty($result)) {
$uniqueField[] = $field;
}
}

} catch (Exception $exception) {
Log::error($exception->getMessage());
}
return Constant::STATUS_FALSE;
return $uniqueField;
}
}
23 changes: 22 additions & 1 deletion src/Services/DBConnectionService.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public function getFields(string $tableName): array
{
$fields = Constant::ARRAY_DECLARATION;
try {
$fieldDetails = DB::select("Describe {$tableName}");
$fieldDetails = DB::select("Describe `$tableName`");
foreach ($fieldDetails as $field) {
$fields[] = $field->Field;
}
Expand Down Expand Up @@ -112,4 +112,25 @@ public function getTableSize(string $tableName): string
}
return Constant::STATUS_FALSE;
}

/**
* Get Field Data Type
* @param string $tableName
* @param string $fieldName
* @return array|bool
*/
public function getFieldDataType(string $tableName, string $fieldName): array|bool
{
try {
$dataType = DB::select("SELECT `DATA_TYPE`, `CHARACTER_MAXIMUM_LENGTH` FROM `INFORMATION_SCHEMA`.`COLUMNS`
WHERE `TABLE_SCHEMA`= '" . env('DB_DATABASE') . "' AND `TABLE_NAME`= '" . $tableName . "' AND `COLUMN_NAME` = '" . $fieldName . "' ");

if (isset($dataType[0]->DATA_TYPE) && $dataType[0]->DATA_TYPE !== null) {
return ['data_type' => $dataType[0]->DATA_TYPE, 'size' => $dataType[0]->CHARACTER_MAXIMUM_LENGTH];
}
} catch (Exception $exception) {
Log::error($exception->getMessage());
}
return Constant::STATUS_FALSE;
}
}
8 changes: 4 additions & 4 deletions src/Services/NamingRuleService.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,14 @@ public function nameHasNoSpace(string $name): string|bool

/**
* Check name only in alphabets.
* @param string $tableName
* @param string $name
* @return string|bool
*/
public function nameHasOnlyAlphabets(string $tableName): string|bool
public function nameHasOnlyAlphabets(string $name): string|bool
{
$name = $this->removeSpecialCharacter($tableName);
$name = str_replace(' ', '', $this->removeSpecialCharacter($name));
if (!ctype_alpha($name)) {
return $this->addSpecialCharacter(preg_replace(Constant::NUMERIC_PATTERN, '', $tableName));
return $this->addSpecialCharacter(preg_replace(Constant::NUMERIC_PATTERN, '', $name));
}
return Constant::STATUS_TRUE;
}
Expand Down
22 changes: 20 additions & 2 deletions src/Services/RuleService.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@ public function __construct(
{
}

/**
* Get Table List
* @return array
*/
public function getTableList() : array
{
return $this->dBConnectionService->getTableList();
}

/**
* Check table name rules
* @return array
Expand Down Expand Up @@ -119,9 +128,18 @@ public function fieldRules(string $tableName): array
{
$checkFields = Constant::ARRAY_DECLARATION;
try {
$filedDetails = $this->dBConnectionService->getFields($tableName);
foreach ($filedDetails as $field) {
$fields = $this->dBConnectionService->getFields($tableName);

foreach ($fields as $field) {
$checkFields[$field] = $this->checkRules($field, Constant::FIELD_RULES);

$fieldDetails = $this->dBConnectionService->getFieldDataType($tableName, $field);

if ($fieldDetails['data_type'] === Constant::DATATYPE_VARCHAR) {
if($fieldDetails['size'] <= Constant::DATATYPE_VARCHAR_SIZE) {
$checkFields[$field] = ["" => __('Lang::messages.standard.error_message.datatype_change')];
}
}
}
} catch (Exception $exception) {
Log::error($exception->getMessage());
Expand Down
2 changes: 1 addition & 1 deletion src/views/constraint.blade.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div class="mx-2 my-1">
<div class="space-x-1">
TABLE NAME : <span
class="px-1 bg-blue-500 text-white">{{ str_replace("_", ' ', strtoupper($data['table'])) }}</span>
class="px-1 bg-blue-500 text-black">{{ $data['table'] }}</span>
</div>

<div class="flex space-x-1 mt-1">
Expand Down
7 changes: 3 additions & 4 deletions src/views/fail_standard_table.blade.php
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
<div class="mt-1">
TABLE NAME : <span
class="px-2 font-bold bg-blue text-white"> {{ str_replace("_", ' ', $tableStatus['table']) }} </span>
TABLE NAME : <span class="px-2 font-bold bg-blue text-white"> {{ str_replace("_", ' ', $tableStatus['table']) }} </span>
@if ($tableStatus['table_comment'])
<div class="mt-0">
<span class="text-white mt-1">suggestion(s)</span>
</div>
<ol class='mt-1 ml-1'>
@foreach ($tableStatus['table_comment'] as $commentKey => $comment)
<li>
<span class="text-yellow">{{ $comment }} </span>
<span class="text-yellow">{{ $comment }}</span>
<span class="text-green">( {{ $commentKey }} )</span>
</li>
@endforeach
Expand All @@ -33,7 +32,7 @@ class="px-2 font-bold bg-blue text-white"> {{ str_replace("_", ' ', $tableStatus
<tr>
<td></td>
<td></td>
<td class="text-yellow">👉 {{ $fieldComment }} ( {{ $solution }} )</td>
<td class="text-yellow flex">👉 {{ $fieldComment }} {{ $solution !== "" ? '(' .$solution. ')' : null }} </td>
</tr>
@endforeach
@else
Expand Down

0 comments on commit eee1893

Please sign in to comment.