From cd4ea422e3c3da4ca217cff1d2d059dd2c3d0324 Mon Sep 17 00:00:00 2001 From: Johnathan Douglas Date: Thu, 13 Jul 2023 17:17:49 -0300 Subject: [PATCH] categories --- app/Console/Commands/UpdateMassiveCommand.php | 8 +- .../DatabaseMassUpdateServiceProvider.php | 53 ++++ app/Database/DatabaseServiceProvider.php | 115 +++++++ app/Database/PostgresConnection.php | 22 ++ .../Query/Grammars/PostgresGrammar.php | 180 +++++++++++ app/Database/Schema/PostgresBuilder.php | 9 + app/Database/UpdateMassive4.php | 13 +- app/Models/Category.php | 26 ++ app/Models/Transaction.php | 8 + app/Tasks/UpdateMassive1Task.php | 26 +- app/Tasks/UpdateMassive5Task.php | 231 +++++++++++++- composer.json | 1 + composer.lock | 92 ++++-- config/app.php | 5 +- database/factories/CategoryFactory.php | 23 ++ ...3_07_07_150457_create_categories_table.php | 27 ++ ...07_07_150557_create_transactions_table.php | 4 + database/seeders/CategorySeeder.php | 19 ++ database/seeders/TransactionSeeder.php | 290 ++++++++++++++++-- 19 files changed, 1068 insertions(+), 84 deletions(-) create mode 100644 app/Database/DatabaseMassUpdateServiceProvider.php create mode 100644 app/Database/DatabaseServiceProvider.php create mode 100644 app/Database/PostgresConnection.php create mode 100644 app/Database/Query/Grammars/PostgresGrammar.php create mode 100644 app/Database/Schema/PostgresBuilder.php create mode 100644 app/Models/Category.php create mode 100644 database/factories/CategoryFactory.php create mode 100644 database/migrations/2023_07_07_150457_create_categories_table.php create mode 100644 database/seeders/CategorySeeder.php diff --git a/app/Console/Commands/UpdateMassiveCommand.php b/app/Console/Commands/UpdateMassiveCommand.php index 0c0edb4..eb143b2 100755 --- a/app/Console/Commands/UpdateMassiveCommand.php +++ b/app/Console/Commands/UpdateMassiveCommand.php @@ -41,7 +41,7 @@ class UpdateMassiveCommand extends Command * 100000 - App\Jobs\UpdateMassive1Job ....... 2m 36s DONE * 1000000 - App\Jobs\UpdateMassive1Job ...... 26m 10s DONE */ - new UpdateMassive1Job(), +// new UpdateMassive1Job(), /** * Atualiza o campo data e valor, mas passando todos os ids das transações, @@ -52,7 +52,7 @@ class UpdateMassiveCommand extends Command * 100000 - App\Jobs\UpdateMassive2Job ........... 1s DONE * 1000000 - App\Jobs\UpdateMassive2Job .......... 15s DONE */ - new UpdateMassive2Job(), +// new UpdateMassive2Job(), /** * Atualiza o campo data e valor, mas o campo data será preenchido com um valor diferente para cada transação, @@ -63,7 +63,7 @@ class UpdateMassiveCommand extends Command * 100000 - App\Jobs\UpdateMassive3Job ....... 2m 44s DONE * 1000000 - App\Jobs\UpdateMassive3Job ...... 27m 10s DONE */ - new UpdateMassive3Job(), +// new UpdateMassive3Job(), /** * Atualiza o campo data e valor, mas o campo data será preenchido com um valor diferente para cada transação, @@ -74,7 +74,7 @@ class UpdateMassiveCommand extends Command * 100000 - App\Jobs\UpdateMassive4Job .......... 8s DONE * 1000000 - App\Jobs\UpdateMassive4Job ...... 1m 15s DONE */ - new UpdateMassive4Job(), +// new UpdateMassive4Job(), /** * Atualiza o campo data e valor, mas o campo data será preenchido com um valor diferente para cada transação, diff --git a/app/Database/DatabaseMassUpdateServiceProvider.php b/app/Database/DatabaseMassUpdateServiceProvider.php new file mode 100644 index 0000000..08aff0b --- /dev/null +++ b/app/Database/DatabaseMassUpdateServiceProvider.php @@ -0,0 +1,53 @@ +applyBeforeQueryCallbacks(); +// +// $sql = $this->grammar->compileMassUpdateWithFrom($this, $values, $uniqueBy); +// +// return $this->connection->massUpdate($sql, $this->cleanBindings( +// $this->grammar->prepareBindingsForMassUpdateWithFrom($this->bindings, $values) +// )); +// }); + + Builder::macro('joinFrom', function (array $items, $tableAlias, $first, $operator = null, $second = null, $type = 'inner', $where = false) { + $table = $this->grammar->compileJoinFrom($this, $items, $tableAlias); + + $bindings = $this->grammar->prepareBindingsJoinFrom($items); + + $this->addBinding($bindings, 'join'); + + return $this->join($this->raw($table), $first, $operator, $second, $type, $where); + }); + + } +} diff --git a/app/Database/DatabaseServiceProvider.php b/app/Database/DatabaseServiceProvider.php new file mode 100644 index 0000000..677f211 --- /dev/null +++ b/app/Database/DatabaseServiceProvider.php @@ -0,0 +1,115 @@ +app['db']); + + Model::setEventDispatcher($this->app['events']); + } + + /** + * Register the service provider. + * + * @return void + */ + public function register() + { + Model::clearBootedModels(); + + $this->registerConnectionServices(); + $this->registerEloquentFactory(); + $this->registerQueueableEntityResolver(); + } + + /** + * Register the primary database bindings. + * + * @return void + */ + protected function registerConnectionServices() + { + // The connection factory is used to create the actual connection instances on + // the database. We will inject the factory into the manager so that it may + // make the connections while they are actually needed and not of before. + $this->app->singleton('db.factory', function ($app) { + return new ConnectionFactory($app); + }); + + // The database manager is used to resolve various connections, since multiple + // connections might be managed. It also implements the connection resolver + // interface which may be used by other components requiring connections. + $this->app->singleton('db', function ($app) { + return new DatabaseManager($app, $app['db.factory']); + }); + + $this->app->bind('db.connection', function ($app) { + return $app['db']->connection(); + }); + + $this->app->bind('db.schema', function ($app) { + return $app['db']->connection()->getSchemaBuilder(); + }); + + $this->app->singleton('db.transactions', function ($app) { + return new DatabaseTransactionsManager; + }); + } + + /** + * Register the Eloquent factory instance in the container. + * + * @return void + */ + protected function registerEloquentFactory() + { + $this->app->singleton(FakerGenerator::class, function ($app, $parameters) { + $locale = $parameters['locale'] ?? $app['config']->get('app.faker_locale', 'en_US'); + + if (! isset(static::$fakers[$locale])) { + static::$fakers[$locale] = FakerFactory::create($locale); + } + + static::$fakers[$locale]->unique(true); + + return static::$fakers[$locale]; + }); + } + + /** + * Register the queueable entity resolver implementation. + * + * @return void + */ + protected function registerQueueableEntityResolver() + { + $this->app->singleton(EntityResolver::class, function () { + return new QueueEntityResolver; + }); + } +} diff --git a/app/Database/PostgresConnection.php b/app/Database/PostgresConnection.php new file mode 100644 index 0000000..de36291 --- /dev/null +++ b/app/Database/PostgresConnection.php @@ -0,0 +1,22 @@ +setConnection($this); + + return $this->withTablePrefix($grammar); + } + + public function massUpdate($query, $bindings = []) + { +// dd($query, $bindings); + return $this->affectingStatement($query, $bindings); + } +} diff --git a/app/Database/Query/Grammars/PostgresGrammar.php b/app/Database/Query/Grammars/PostgresGrammar.php new file mode 100644 index 0000000..d4445a6 --- /dev/null +++ b/app/Database/Query/Grammars/PostgresGrammar.php @@ -0,0 +1,180 @@ +from)); + } + + public function getTableName(Builder $query) + { + return current(preg_split('/\s+as\s+/i', $query->from)); + } + + /** + * @param array $items + * + * Ex: + * update transactions as t + * set + * date = c.date, + * value = c.value + * from ( values + * (1, '2023-01-05 00:00:00'::timestamp, 23.44), + * (2, '2023-01-03 00:00:00'::timestamp, 23.44) + * ) as c (id, date, value) + * where t.id = c.id"; + * @throws \Exception + */ + + public function compileMassUpdateWithFrom(Builder $query, array $items, string $uniqueBy = 'id') + { + if (count($items) === 0) { + throw new \Exception('values is empty'); + } + + $table = $this->wrapTable($query->from); + $tableName = $this->getTableName($query); + $tableOrAlias = $this->getTableOrAlias($query); + $tableAuxName = 'mu'; + + $properties = array_keys($items[0]); + + $columnTypes = $this->getColumnTypes($tableName, $properties); + + $columnsSql = [ +// $this->wrap('type') . ' = ("mu"."id"::int + "t"."type" + 2)::int', +// $this->wrap('status') . ' = (case "mu"."id"::int when 1 then \'paid\' end)::text', + ]; + foreach ($properties as $property) { + if ($property !== $uniqueBy) { + $columnsSql[] = $this->wrap($property) . ' = ' . $this->wrap("$tableAuxName.$property") . '::' . $columnTypes[$property]; + } + } + $columns = implode(', ', $columnsSql); + + $parameters = []; + foreach ($items as $item) { + if (!isset($item[$uniqueBy])) { + throw new \Exception('column \'' . $uniqueBy . '\' not found'); + } + + $parametersItem = []; + foreach ($properties as $property) { + $parametersItem[] = $this->parameter($item[$property]); + } + + $parameters[] = '(' . implode(', ', $parametersItem) . ')'; + } + $parameters = implode(', ', $parameters); + + $parametersColumns = implode(', ', $properties); + + $from = " from (values $parameters) as $tableAuxName ($parametersColumns)"; + + $query->where("$tableOrAlias.$uniqueBy", '=', $query->raw($this->wrap("$tableAuxName.$uniqueBy") . '::' . $columnTypes[$uniqueBy])); + + $where = $this->compileWheres($query); + + return "update {$table} set {$columns}{$from} {$where}"; + } + + public function prepareBindingsForMassUpdateWithFrom(array $bindings, array $items) + { + $properties = array_keys($items[0]); + + $values = []; + foreach ($items as $item) { + foreach ($properties as $property) { + $values[] = $item[$property]; + } + } + + $values = collect($values) + ->map(function ($value, $column) { + return is_array($value) || ($this->isJsonSelector($column) && !$this->isExpression($value)) + ? json_encode($value) + : $value; + }) + ->all(); + + $cleanBindings = Arr::except($bindings, 'select'); + + return array_values( + array_merge($values, Arr::flatten($cleanBindings)) + ); + } + + private function getColumnTypes(string $tableName, array $columns): array + { + $key = vsprintf('column;types;%s;%s', [ + $tableName, + implode(';', $columns) + ]); + + return Cache::store('array')->rememberForever($key, function () use ($tableName, $columns) { + $schemaColumns = DB::table('information_schema.columns') + ->select([ + 'column_name', + 'udt_name', + ]) + ->where('table_name', '=', $tableName) + ->whereIn('column_name', $columns) + ->get(); + + $types = []; + foreach ($schemaColumns as $schemaColumn) { + $types[$schemaColumn->column_name] = $schemaColumn->udt_name; + } + + return $types; + }); + } + + public function compileJoinFrom(Builder $query, array $items, $tableAlias) + { + if (count($items) === 0) { + throw new \Exception('items is empty'); + } + + $values = []; + $properties = array_keys($items[0]); + foreach ($items as $item) { + $valuesItem = []; + foreach ($properties as $property) { + $valuesItem[] = $this->parameter($item[$property]); + } + + $values[] = '(' . implode(', ', $valuesItem) . ')'; + } + + $values = implode(', ', $values); + $properties = implode(', ', $properties); + + return "(values $values) as $tableAlias ($properties)"; + } + + public function prepareBindingsJoinFrom(array $items) + { + $values = []; + + $properties = array_keys($items[0]); + foreach ($items as $item) { + foreach ($properties as $property) { + $values[] = $item[$property]; + } + } + + return $values; + } +} diff --git a/app/Database/Schema/PostgresBuilder.php b/app/Database/Schema/PostgresBuilder.php new file mode 100644 index 0000000..8fa0343 --- /dev/null +++ b/app/Database/Schema/PostgresBuilder.php @@ -0,0 +1,9 @@ +enableQueryLog(); +// DB::table('t_maquinetas as (,....)') +// ->join( 'from ()') +// UPDATE t_maquinetas +//SET t_terminal_id = sub.id +// FROM (SELECT id, id_antigo FROM t_terminal WHERE tipo = 1) as sub +//WHERE sub.id_antigo = t_pos_id AND +// (t_pdv_id IS NULL); + + $db->table($table) ->whereIn($primaryKeyName, $primaryKeyValues) ->update($values); - -// dd($db->getQueryLog()); } } diff --git a/app/Models/Category.php b/app/Models/Category.php new file mode 100644 index 0000000..ef54b17 --- /dev/null +++ b/app/Models/Category.php @@ -0,0 +1,26 @@ + + */ + protected $fillable = [ + 'name', + ]; +} diff --git a/app/Models/Transaction.php b/app/Models/Transaction.php index 5912436..95376fe 100755 --- a/app/Models/Transaction.php +++ b/app/Models/Transaction.php @@ -5,6 +5,12 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +/** + * @property int id + * @property int date + * + * @property int idade + */ class Transaction extends Model { use HasFactory; @@ -37,4 +43,6 @@ class Transaction extends Model protected $casts = [ 'date' => 'datetime', ]; + + } diff --git a/app/Tasks/UpdateMassive1Task.php b/app/Tasks/UpdateMassive1Task.php index 80572b2..f4a0465 100755 --- a/app/Tasks/UpdateMassive1Task.php +++ b/app/Tasks/UpdateMassive1Task.php @@ -4,26 +4,36 @@ namespace App\Tasks; use App\Models\Transaction; use Carbon\Carbon; +use Illuminate\Support\Facades\DB; class UpdateMassive1Task { public function handle() { + Transaction::query() ->select([ 'id', ]) ->where('id', '>', 0) ->chunkById(1000, function ($transactions) { - foreach ($transactions as $transaction) { - Transaction::query() - ->where('id', '=', $transaction->id) - ->update([ - 'date' => Carbon::now(), - 'value' => 1, - ]); - } + +// DB::beginTransaction(); +// try { + foreach ($transactions as $transaction) { + Transaction::query() + ->where('id', '=', $transaction->id) + ->update([ + 'date' => Carbon::now(), + 'value' => 1, + ]); + } + DB::commit(); +// } catch (\Exception $exception) { +// DB::rollBack(); +// } + }); } diff --git a/app/Tasks/UpdateMassive5Task.php b/app/Tasks/UpdateMassive5Task.php index 9c1ca7f..d7e848f 100644 --- a/app/Tasks/UpdateMassive5Task.php +++ b/app/Tasks/UpdateMassive5Task.php @@ -2,10 +2,10 @@ namespace App\Tasks; -use App\Database\UpdateMassive5; use App\Models\Transaction; use Carbon\Carbon; use Illuminate\Support\Collection; +use Illuminate\Support\Facades\DB; class UpdateMassive5Task { @@ -20,22 +20,235 @@ class UpdateMassive5Task ->where('id', '>', 0) ->chunkById(1000, function ($transactions) { + $values = []; /** @var Collection $transactions */ foreach ($transactions as $transaction) { $transaction->date = Carbon::now()->subDays(random_int(1, 3)); $transaction->value = 10 + random_int(0, 10); - $config[] = [ - 'primary_key' => $transaction->id, - 'columns' => [ - 'date' => "'$transaction->date'::timestamp", - 'value' => $transaction->value, - ] +// $values[] = [ +// 'primary_key' => $transaction->id, +// 'columns' => [ +// 'date' => "'$transaction->date'::timestamp", +// 'value' => $transaction->value, +// ] +// ]; + + $values[] = [ + 'id' => $transaction->id, + 'date' => $transaction->date, + 'value' => $transaction->value, ]; } - $updateMassive2 = new UpdateMassive5(); - $updateMassive2->apply('transactions', 'id', $config); +// $values = [ +// [ +// 'id' => 1, +// 'date' => Carbon::now(), +// 'value' => 10, +// ], +// [ +// 'id' => 2, +// 'date' => '2023-01-02', +// 'value' => 20, +//// 'value' => DB::raw('t.value + 1'), +// ] +// ]; +// +// $values = [ +//// [ +//// 'id' => DB::raw('1::int8'), +//// 'date' => DB::raw('\'' . Carbon::now()->format('Y-m-d H:i:s') . '\'::timestamp'), +//// 'value' => DB::raw('10::numeric'), +//// ], +// [ +// 'id' => 2, +// 'date' => '2023-01-02', +// 'value' => 20, +//// 'value' => DB::raw('t.value + 1'), +// ] +// ]; + + + DB::enableQueryLog(); + +// DB::table('transactions') +// ->insert($values); + + $values = [ + [ + 'id' => 1, + 'value' => 20, +// 'day' => 2, + ], + [ + 'id' => 2, + 'value' => 30, +// 'day' => 5, + ], + [ + 'value' => 30, + 'id' => 3, +// 'day' => 3, + + ], + ]; + + + DB::table('transactions as t') + ->joinFrom($values, 'm', DB::raw('m.id::bigint'), '=', 't.id') + ->updateFrom([ + 'value' => DB::raw('m.value::decimal'), + ]); + + + DB::table('transactions as t') + ->massUpdate([ + [ + 'id' => 1, + 'value' => DB::raw('20::float'), + 'date' => '2023-01-01', + ], + [ + 'id' => 2, + 'value' => 30, + 'date' => '2023-01-01', + ], + [ + 'id' => 1, + 'value' => 30, + 'date' => '2023-01-01', + ], + ], 'id'); + + +// $properties = array_keys($values[0]); +// $x = []; +// $propertiesCount = count($properties); +// foreach ($values as $item) { +// foreach ($properties as $property) { +// if (count(array_keys($item)) !== $propertiesCount) { +// throw new \Exception('a quantidade de propriedades é diferente'); +// } +// +// $x [] = $item[$property]; +// } +// } +// +//// dd($x); +//// DB::table('transactions as t') +//// ->massUpdate($values, $uniqueKeys = ['id', 'value'], ); +// +// DB::table('transaction as t') +// ->whereIn('id', [1,2,3]) +// ->update([ +// 'value'=> DB::raw('value + (case id when 1 then 2.0 when 2 then 5.0 when 3 then 2.32 end)') +// ]); + + +// $table = DB::raw('(values (?, ?), (?, ?), (?, ?)) as "m" (' . implode(', ', $properties) . ')'); + + DB::enableQueryLog(); + DB::table('transactions as t') +// ->join($table, DB::raw('m.id::bigint'), '=', 't.id') +// ->addBinding($x) + ->joinFrom($values, 'm', DB::raw('m.id::bigint'), '=', 't.id') +// ->where('t.date', '>', Carbon::now()->subDays(5)) + ->updateFrom([ +// "value" => DB::raw('t.value + "m"."value"::decimal'), +// "date" => DB::raw('(t.date::timestamp + (interval \'1\' day * m.day::int))'), + "value" => DB::raw('m.value::decimal'), + ]); + + dd(DB::getQueryLog()); + dd('aa'); + +// t.value = m.value + 1; +// t.value = m.value + 1; + + + DB::table('transactions as t') + ->joinFrom($values, 'm', DB::raw('m.id::bigint'), '=', 't.id') + ->updateFrom([ + 'value' => DB::raw('m.value::decimal'), + ]); + dd(DB::getQueryLog()); + + $values = [ + [ + 'id' => 1, + 'date' => Carbon::now(), + 'value' => 20, + ], + [ + 'id' => 2, + 'date' => '2023-01-02', + 'value' => 30, + ], + ]; + + + DB::table('transactions as t') + ->joinFrom($values, 'm', DB::raw('m.id::bigint'), '=', 't.id') + ->updateFrom([ + 'value' => DB::raw('(m.value::decimal + 1)::decimal'), + 'date' => DB::raw('m.date::timestamp'), + 'type' => 2, + 'status' => DB::raw('case t.id when 1 then \'paid\' else t.status end'), + ]); + + +// DB::table('transactions as t') +// ->join(DB::raw('(values (1,\'2019-01-15 10:00:00\',10), (2,\'2019-01-15 10:00:00\', 20) ) as mu (id, value, date)'), 'mu.id', '=', 't.id') +// ->updateFrom([ +// 'value' => DB::raw('(mu.value::decimal + 1)::decimal'), +// 'date' => DB::raw('mu.date::timestamp'), +// 'type' => 2, +// 'status' => DB::raw('case t.id when 1 then \'paid\' else t.status end'), +// ]); + + dd(DB::getQueryLog()); + dd('aa'); +// DB::table('transactions as t') +// ->massUpdateWithFrom( +// values: [ +// [ +// 'id' => 1, +// 'date' => Carbon::now(), +// 'value' => 10, +// ] +// ], +//// valuesAlias: 'mu', +//// updateColumns: [ +//// 'date' => 'mu.date::timestamp', +//// 'value' => 'mu.value + 1', +//// 'type' => '2', +//// 'fee' => '(t.value / mu.value) * 0.1', +//// ] +// ); + +// $queryLog = DB::getQueryLog(); +// +// $sql = $queryLog[1]['query']; +// $bindings = $queryLog[1]['bindings']; +// +// foreach ($bindings as $i => $binding) { +// if ($binding instanceof \DateTimeInterface) { +// $bindings[$i] = $binding->format('\'Y-m-d H:i:s\''); +// } else { +// $bindings[$i] = "'$binding'"; +// } +// } +// +// $sql = vsprintf(str_replace('?', '%s', $sql), $bindings); +// +// dd($sql); + +// +// dd('aa'); +// $updateMassive2 = new UpdateMassive5(); +// $updateMassive2->apply('transactions', 'id', $values); }); } + } diff --git a/composer.json b/composer.json index e1fb449..95a94ab 100755 --- a/composer.json +++ b/composer.json @@ -7,6 +7,7 @@ "require": { "php": "^8.1", "guzzlehttp/guzzle": "^7.2", + "johdougss/laravel-mass-update": "^1.0", "laravel/framework": "^10.10", "laravel/sanctum": "^3.2", "laravel/tinker": "^2.8" diff --git a/composer.lock b/composer.lock index 50d80b6..491b713 100755 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "aa322c53454393ed775cfe4807d54a50", + "content-hash": "d147bec59f72c112c82016e4eaacc88b", "packages": [ { "name": "brick/math", @@ -975,17 +975,47 @@ "time": "2021-10-07T12:57:01+00:00" }, { - "name": "laravel/framework", - "version": "v10.14.1", + "name": "johdougss/laravel-mass-update", + "version": "1.0.1", "source": { "type": "git", - "url": "https://github.com/laravel/framework.git", - "reference": "6f89a2b74b232d8bf2e1d9ed87e311841263dfcb" + "url": "https://github.com/johdougss/laravel-mass-update.git", + "reference": "4e8e7b0b960e6185108aecd19d351a5dd65296fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/6f89a2b74b232d8bf2e1d9ed87e311841263dfcb", - "reference": "6f89a2b74b232d8bf2e1d9ed87e311841263dfcb", + "url": "https://api.github.com/repos/johdougss/laravel-mass-update/zipball/4e8e7b0b960e6185108aecd19d351a5dd65296fc", + "reference": "4e8e7b0b960e6185108aecd19d351a5dd65296fc", + "shasum": "" + }, + "require": { + "illuminate/database": "*" + }, + "type": "library", + "autoload": { + "psr-4": { + "Johdougss\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "support": { + "issues": "https://github.com/johdougss/laravel-mass-update/issues", + "source": "https://github.com/johdougss/laravel-mass-update/tree/1.0.1" + }, + "time": "2023-07-13T20:11:49+00:00" + }, + { + "name": "laravel/framework", + "version": "v10.15.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/framework.git", + "reference": "c7599dc92e04532824bafbd226c2936ce6a905b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/framework/zipball/c7599dc92e04532824bafbd226c2936ce6a905b8", + "reference": "c7599dc92e04532824bafbd226c2936ce6a905b8", "shasum": "" }, "require": { @@ -1172,7 +1202,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2023-06-28T14:25:16+00:00" + "time": "2023-07-11T13:43:52+00:00" }, { "name": "laravel/sanctum", @@ -5578,16 +5608,16 @@ }, { "name": "filp/whoops", - "version": "2.15.2", + "version": "2.15.3", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "aac9304c5ed61bf7b1b7a6064bf9806ab842ce73" + "reference": "c83e88a30524f9360b11f585f71e6b17313b7187" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/aac9304c5ed61bf7b1b7a6064bf9806ab842ce73", - "reference": "aac9304c5ed61bf7b1b7a6064bf9806ab842ce73", + "url": "https://api.github.com/repos/filp/whoops/zipball/c83e88a30524f9360b11f585f71e6b17313b7187", + "reference": "c83e88a30524f9360b11f585f71e6b17313b7187", "shasum": "" }, "require": { @@ -5637,7 +5667,7 @@ ], "support": { "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.15.2" + "source": "https://github.com/filp/whoops/tree/2.15.3" }, "funding": [ { @@ -5645,7 +5675,7 @@ "type": "github" } ], - "time": "2023-04-12T12:00:00+00:00" + "time": "2023-07-13T12:00:00+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -5700,16 +5730,16 @@ }, { "name": "laravel/pint", - "version": "v1.10.3", + "version": "v1.10.4", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "c472786bca01e4812a9bb7933b23edfc5b6877b7" + "reference": "f56798088068af8bd75a8f2c4ecae022990fdf75" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/c472786bca01e4812a9bb7933b23edfc5b6877b7", - "reference": "c472786bca01e4812a9bb7933b23edfc5b6877b7", + "url": "https://api.github.com/repos/laravel/pint/zipball/f56798088068af8bd75a8f2c4ecae022990fdf75", + "reference": "f56798088068af8bd75a8f2c4ecae022990fdf75", "shasum": "" }, "require": { @@ -5720,7 +5750,7 @@ "php": "^8.1.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.18.0", + "friendsofphp/php-cs-fixer": "^3.21.1", "illuminate/view": "^10.5.1", "laravel-zero/framework": "^10.0.2", "mockery/mockery": "^1.5.1", @@ -5762,20 +5792,20 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2023-06-20T15:55:03+00:00" + "time": "2023-07-11T15:18:27+00:00" }, { "name": "laravel/sail", - "version": "v1.23.0", + "version": "v1.23.1", "source": { "type": "git", "url": "https://github.com/laravel/sail.git", - "reference": "a2e046f748e87d3ef8b2b381e0e5c5a11f34e46b" + "reference": "62582606f80466aa81fba40b193b289106902853" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/sail/zipball/a2e046f748e87d3ef8b2b381e0e5c5a11f34e46b", - "reference": "a2e046f748e87d3ef8b2b381e0e5c5a11f34e46b", + "url": "https://api.github.com/repos/laravel/sail/zipball/62582606f80466aa81fba40b193b289106902853", + "reference": "62582606f80466aa81fba40b193b289106902853", "shasum": "" }, "require": { @@ -5827,7 +5857,7 @@ "issues": "https://github.com/laravel/sail/issues", "source": "https://github.com/laravel/sail" }, - "time": "2023-06-16T21:20:12+00:00" + "time": "2023-06-28T18:31:28+00:00" }, { "name": "mockery/mockery", @@ -6495,16 +6525,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.2.3", + "version": "10.2.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "35c8cac1734ede2ae354a6644f7088356ff5b08e" + "reference": "68484779b5a2ed711fbdeba6ca01910d87acdff2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/35c8cac1734ede2ae354a6644f7088356ff5b08e", - "reference": "35c8cac1734ede2ae354a6644f7088356ff5b08e", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/68484779b5a2ed711fbdeba6ca01910d87acdff2", + "reference": "68484779b5a2ed711fbdeba6ca01910d87acdff2", "shasum": "" }, "require": { @@ -6576,7 +6606,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.2.3" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.2.4" }, "funding": [ { @@ -6592,7 +6622,7 @@ "type": "tidelift" } ], - "time": "2023-06-30T06:17:38+00:00" + "time": "2023-07-10T04:06:08+00:00" }, { "name": "sebastian/cli-parser", diff --git a/config/app.php b/config/app.php index 4c231b4..6415a10 100755 --- a/config/app.php +++ b/config/app.php @@ -42,7 +42,7 @@ return [ | */ - 'debug' => (bool) env('APP_DEBUG', false), + 'debug' => (bool)env('APP_DEBUG', false), /* |-------------------------------------------------------------------------- @@ -168,6 +168,9 @@ return [ // App\Providers\BroadcastServiceProvider::class, App\Providers\EventServiceProvider::class, App\Providers\RouteServiceProvider::class, + + App\Database\DatabaseMassUpdateServiceProvider::class, +// Johdougss\Database\DatabaseMassUpdateServiceProvider::class, ])->toArray(), /* diff --git a/database/factories/CategoryFactory.php b/database/factories/CategoryFactory.php new file mode 100644 index 0000000..9ac44f4 --- /dev/null +++ b/database/factories/CategoryFactory.php @@ -0,0 +1,23 @@ + + */ +class CategoryFactory extends Factory +{ + /** + * Define the model's default state. + * + * @return array + */ + public function definition(): array + { + return [ + 'name' => 'category ' . fake()->numerify('######') + ]; + } +} diff --git a/database/migrations/2023_07_07_150457_create_categories_table.php b/database/migrations/2023_07_07_150457_create_categories_table.php new file mode 100644 index 0000000..69b3d00 --- /dev/null +++ b/database/migrations/2023_07_07_150457_create_categories_table.php @@ -0,0 +1,27 @@ +id(); + $table->string('name', 20); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('categories'); + } +}; diff --git a/database/migrations/2023_07_07_150557_create_transactions_table.php b/database/migrations/2023_07_07_150557_create_transactions_table.php index 2335252..194e16f 100755 --- a/database/migrations/2023_07_07_150557_create_transactions_table.php +++ b/database/migrations/2023_07_07_150557_create_transactions_table.php @@ -5,6 +5,7 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { + /** * Run the migrations. */ @@ -13,6 +14,9 @@ return new class extends Migration { Schema::create('transactions', function (Blueprint $table) { $table->id(); $table->decimal('value', 12, 2); + $table->integer('type')->default(1); + $table->string('status', 10)->default('pending'); + $table->bigInteger('category_id')->nullable(); $table->timestamp('date'); $table->timestamps(); }); diff --git a/database/seeders/CategorySeeder.php b/database/seeders/CategorySeeder.php new file mode 100644 index 0000000..5d0f948 --- /dev/null +++ b/database/seeders/CategorySeeder.php @@ -0,0 +1,19 @@ +make(); + Transaction::query()->insert($categories->toArray()); + } +} diff --git a/database/seeders/TransactionSeeder.php b/database/seeders/TransactionSeeder.php index 47aae56..e67985a 100755 --- a/database/seeders/TransactionSeeder.php +++ b/database/seeders/TransactionSeeder.php @@ -4,6 +4,7 @@ namespace Database\Seeders; use App\Models\Transaction; use Illuminate\Database\Seeder; +use Illuminate\Support\Facades\DB; class TransactionSeeder extends Seeder { @@ -13,44 +14,262 @@ class TransactionSeeder extends Seeder public function run(): void { $count = config('update-massive.items_count'); + $type = 3; if ($type === 1) { - - /** - * insert unit - * 1000 - Database\Seeders\TransactionSeeder ...... 1,443.86 ms DONE - * 10000 - Database\Seeders\TransactionSeeder ..... 14,256.24 ms DONE - * 100000 - Database\Seeders\TransactionSeeder .... 158,413.75 ms DONE - * 1000000 - - */ - Transaction::factory($count)->create(); + $this->type1($count); } if ($type === 2) { - - /** - * insert multiple - * 1000 - Database\Seeders\TransactionSeeder ......... 96.11 ms DONE - * 10000 - Database\Seeders\TransactionSeeder ........ 887.48 ms DONE - * 100000 - SQLSTATE[HY000]: General error: 7 number of parameters must be between 0 and 65535 - * 1000000 - SQLSTATE[HY000]: General error: 7 number of parameters must be between 0 and 65535 - */ - $transactions = Transaction::factory($count)->make(); - Transaction::query()->insert($transactions->toArray()); + $this->type2($count); } if ($type === 3) { + $this->type3($count); + } - /** - * Limit insert sql string - * insert multiple block - * - * 1000 - Database\Seeders\TransactionSeeder ......... 97.71 ms DONE - * 10000 - Database\Seeders\TransactionSeeder ........ 833.27 ms DONE - * 100000 - Database\Seeders\TransactionSeeder ...... 8,256.29 ms DONE - * 1000000 - Database\Seeders\TransactionSeeder ..... 95,473.46 ms DONE - */ + if ($type === 4) { + $this->type4($count); + } + + if ($type === 5) { + $this->type5($count); + } + + if ($type === 6) { + $this->type6($count); + } + + if ($type === 7) { + $this->type7($count); + } + } + + /** + * @param mixed $count + * @return void + */ + public function type1(mixed $count): void + { + /** + * insert unit + * 1000 - Database\Seeders\TransactionSeeder ...... 1,443.86 ms DONE + * 10000 - Database\Seeders\TransactionSeeder ..... 14,256.24 ms DONE + * 100000 - Database\Seeders\TransactionSeeder .... 158,413.75 ms DONE + * 1000000 - + * + * 1. insert into transactions (id, value, date) values (1, 10, '2023-04-01'); + * - reconstroi os indices, verifica chave, view materializada + * + * 2. insert into transactions (id, value, date) values (2, 20, '2023-04-02'); + * - reconstroi os indices, verifica chave, view materializada + */ +// DB::enableQueryLog(); + Transaction::factory($count)->create(); +// dd(DB::getQueryLog()); + +// $result = DB::getQueryLog(); +// dump(collect($result)->sum('time')); + } + + /** + * @param mixed $count + */ + public function type2(mixed $count): void + { + /** + * insert multiple + * 1000 - Database\Seeders\TransactionSeeder ......... 96.11 ms DONE + * 10000 - Database\Seeders\TransactionSeeder ........ 887.48 ms DONE + * 100000 - SQLSTATE[HY000]: General error: 7 number of parameters must be between 0 and 65535 + * 1000000 - SQLSTATE[HY000]: General error: 7 number of parameters must be between 0 and 65535 + */ + $transactions = Transaction::factory($count)->make(); + Transaction::query()->insert($transactions->toArray()); + } + + + /** + * Limit insert sql string + * insert multiple block + * + * 1000 - Database\Seeders\TransactionSeeder ......... 97.71 ms DONE + * 10000 - Database\Seeders\TransactionSeeder ........ 833.27 ms DONE + * 100000 - Database\Seeders\TransactionSeeder ...... 8,256.29 ms DONE + * 1000000 - Database\Seeders\TransactionSeeder ..... 95,473.46 ms DONE + */ + private function type3(mixed $count) + { + + $block = 1000; + while ($count > 0) { + + if ($count < $block) { + $block = $count; + } + + $transactions = Transaction::factory($block)->make(); + Transaction::query()->insert($transactions->toArray()); + // insert into values ( ...), (....), ... 1000 + // commit + + // insert into values ( ...), (....), ... 1000 + // commit + + // insert into values ( ...), (....), ... 1000 + // commit + + $count -= $block; + } + + } + + /** + * insert unit + * 1000 - Database\Seeders\TransactionSeeder ...... 391.11 ms DONE + * 10000 - Database\Seeders\TransactionSeeder ..... 3,741.94 ms DONE + * 100000 - Database\Seeders\TransactionSeeder .... 38,605.27 ms DONE + * 1000000 - + * + * 1. insert into transactions (id, value, date) values (1, 10, '2023-04-01'); + * 2. insert into transactions (id, value, date) values (2, 20, '2023-04-02'); + * .... 100.000 + * + * - reconstroi os indices, verifica chave, view materializada + */ + private function type4(int $count) + { + DB::beginTransaction(); + try { + Transaction::factory($count)->create(); + DB::commit(); + } catch (\Exception $exception) { + DB::rollBack(); + } + } + + /** + * insert unit + * 1000 - Database\Seeders\TransactionSeeder ...... 380.20 ms DONE + * 10000 - Database\Seeders\TransactionSeeder ..... 3,716.59 ms DONE + * 100000 - Database\Seeders\TransactionSeeder .... 39,143.04 ms DONE + * 1000000 - + * + * 1. insert into transactions (id, value, date) values (1, 10, '2023-04-01'); + * 2. insert into transactions (id, value, date) values (2, 20, '2023-04-02'); + * .... 1.000 commit + * - reconstroi os indices, verifica chave, view materializada + * + * 1001. insert into transactions (id, value, date) values (1, 10, '2023-04-01'); + * 1002. insert into transactions (id, value, date) values (2, 20, '2023-04-02'); + * .... 1.000 commit + * - reconstroi os indices, verifica chave, view materializada + * + */ + private function type5(mixed $count) + { + $block = 1000; + while ($count > 0) { + + if ($count < $block) { + $block = $count; + } + + DB::beginTransaction(); + try { + Transaction::factory($block)->create(); + + DB::commit(); +// echo 'commit' . PHP_EOL; + $count -= $block; + } catch (\Exception $exception) { + DB::rollBack(); + } + } + } + + /** + * + * PDO + * Prepared statement insert verificar + * + * PREPARE transactions_plan (decimal, timestamp) AS + * INSERT INTO transactions (value, date) + * VALUES ($1, $2); + * + * EXECUTE transactions_plan(23.44, '2023-01-05 00:00:00'::timestamp); + * + * 1000 - Database\Seeders\TransactionSeeder ...... 1,341.07 ms DONE + * 10000 - Database\Seeders\TransactionSeeder ..... 13,415.95 ms DONE + * 100000 - Database\Seeders\TransactionSeeder ............ - ms DONE + * 1000000 - Database\Seeders\TransactionSeeder ............ - ms DONE + * + * 1000 - Database\Seeders\TransactionSeeder ........ 173.91 ms DONE + * 10000 - Database\Seeders\TransactionSeeder ...... 1,591.86 ms DONE + * 100000 - Database\Seeders\TransactionSeeder ......16,331.67 ms DONE + * 1000000 - Database\Seeders\TransactionSeeder ............ - ms DONE + * + * @param mixed $count + * @return void + */ + private function type6(mixed $count) + { +// DB::enableQueryLog(); + +// DB::beginTransaction(); +// +// try { + +// DB::enableQueryLog(); + + $sql1 = 'PREPARE transactions_plan5 (decimal, timestamp) AS INSERT INTO transactions (value, date) VALUES ($1::decimal, $2::timestamp)'; + DB::unprepared($sql1); + + $transactions = Transaction::factory($count)->make(); + +// $sql2 = 'EXECUTE transactions_plan5 (?, ?)'; + + foreach ($transactions as $transaction) { + $sql3 = vsprintf('EXECUTE transactions_plan5 (%s, \'%s\')', [ + (float)$transaction->value, + $transaction->date->format('Y-m-d H:i:s') + ]); + DB::unprepared($sql3); + +// $dateFormatted = $transaction->date->format('Y-m-d H:i:s'); +// $bindings = [ +// (float)$transaction->value, +// $dateFormatted, +// ]; + +// DB::statement($sql2, $bindings); + } + +// dd(DB::getQueryLog()); +// DB::commit(); +// } catch (\Exception $exception) { +// DB::rollBack(); +// } + +// $result = DB::getQueryLog(); +// dump(collect($result)->sum('time')); + } + + /** + * Limit insert sql string + * insert multiple block + * + * 1000 - Database\Seeders\TransactionSeeder ......... 97.71 ms DONE + * 10000 - Database\Seeders\TransactionSeeder ........ 858.70 ms DONE + * 100000 - Database\Seeders\TransactionSeeder ...... 8,819.44 ms DONE + * 1000000 - Database\Seeders\TransactionSeeder ..... 87,649.37 ms DONE + */ + private function type7(mixed $count) + { + + DB::beginTransaction(); + try { $block = 1000; while ($count > 0) { @@ -62,8 +281,23 @@ class TransactionSeeder extends Seeder $transactions = Transaction::factory($block)->make(); Transaction::query()->insert($transactions->toArray()); + // insert into values ( ...), (....), ... 1000 + // insert into values ( ...), (....), ... 1000 + // insert into values ( ...), (....), ... 1000 + $count -= $block; } + + DB::commit(); + // commit + } catch (\Exception $exception) { + DB::rollBack(); } + + } + + private function champion($count) + { + $this->type3($count); } }