@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
DB::statement('ALTER TABLE geo_locations ADD COLUMN source_code text');
|
||||
DB::statement('CREATE UNIQUE INDEX geo_source_parent_code_uq ON geo_locations(source_system, parent_id, location_type, source_code) NULLS NOT DISTINCT WHERE deleted_at IS NULL AND source_code IS NOT NULL');
|
||||
DB::statement('CREATE INDEX geo_parent_type_name_idx ON geo_locations(parent_id, location_type, name) WHERE deleted_at IS NULL');
|
||||
DB::unprepared(<<<'SQL'
|
||||
CREATE OR REPLACE FUNCTION enforce_geo_hierarchy() RETURNS trigger LANGUAGE plpgsql AS $$
|
||||
DECLARE parent_type text; expected_type text;
|
||||
BEGIN
|
||||
PERFORM pg_advisory_xact_lock(280926,150000);
|
||||
IF NEW.deleted_at IS NOT NULL THEN RETURN NEW; END IF;
|
||||
IF NEW.location_type='country' AND NEW.parent_id IS NOT NULL THEN
|
||||
RAISE EXCEPTION 'Country cannot have a parent';
|
||||
END IF;
|
||||
expected_type := CASE NEW.location_type WHEN 'province' THEN 'country' WHEN 'district' THEN 'province' WHEN 'admin_post' THEN 'district' WHEN 'locality' THEN 'admin_post' END;
|
||||
IF NEW.parent_id IS NOT NULL THEN
|
||||
SELECT location_type INTO parent_type FROM geo_locations WHERE id=NEW.parent_id AND deleted_at IS NULL;
|
||||
IF parent_type IS NULL OR (expected_type IS NOT NULL AND parent_type<>expected_type) THEN
|
||||
RAISE EXCEPTION 'Invalid geographic parent';
|
||||
END IF;
|
||||
IF EXISTS(WITH RECURSIVE ancestors AS (
|
||||
SELECT id,parent_id,ARRAY[id] as visited FROM geo_locations WHERE id=NEW.parent_id
|
||||
UNION ALL SELECT g.id,g.parent_id,a.visited||g.id FROM geo_locations g JOIN ancestors a ON g.id=a.parent_id WHERE NOT g.id=ANY(a.visited)
|
||||
) SELECT 1 FROM ancestors WHERE id=NEW.id) THEN RAISE EXCEPTION 'Geographic cycle'; END IF;
|
||||
ELSIF expected_type IS NOT NULL AND NEW.source_system='cartografia-workbook' THEN
|
||||
RAISE EXCEPTION 'Workbook administrative node requires a parent';
|
||||
END IF;
|
||||
IF EXISTS(SELECT 1 FROM geo_locations c WHERE c.parent_id=NEW.id AND c.deleted_at IS NULL AND
|
||||
CASE c.location_type WHEN 'province' THEN 'country' WHEN 'district' THEN 'province' WHEN 'admin_post' THEN 'district' WHEN 'locality' THEN 'admin_post' END <> NEW.location_type) THEN
|
||||
RAISE EXCEPTION 'Geographic children incompatible with new level';
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END $$;
|
||||
CREATE TRIGGER geo_hierarchy_guard BEFORE INSERT OR UPDATE OF parent_id,location_type,deleted_at,source_system ON geo_locations FOR EACH ROW EXECUTE FUNCTION enforce_geo_hierarchy();
|
||||
SQL);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
if (DB::table('geo_locations')->whereNotNull('source_code')->exists()) {
|
||||
throw new RuntimeException('Preserve imported source codes before rollback.');
|
||||
}
|
||||
DB::statement('DROP TRIGGER geo_hierarchy_guard ON geo_locations');
|
||||
DB::statement('DROP FUNCTION enforce_geo_hierarchy()');
|
||||
DB::statement('DROP INDEX geo_source_parent_code_uq');
|
||||
DB::statement('DROP INDEX geo_parent_type_name_idx');
|
||||
DB::statement('ALTER TABLE geo_locations DROP COLUMN source_code');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Sector;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class InvestmentAreaSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
DB::transaction(function () {
|
||||
DB::select('SELECT pg_advisory_xact_lock(290926, 100000)');
|
||||
foreach (['Turismo', 'Mineração', 'Infra-estruturas', 'Energia', 'Mercado Financeiro', 'Fintech', 'Imobiliário', 'Agronegócio', 'Bens de Consumo e Franquias', 'Tecnologias de Informação'] as $name) {
|
||||
$key = str_replace('-', '', Str::slug($name));
|
||||
$exists = Sector::withTrashed()->get(['name'])->contains(fn ($sector) => str_replace('-', '', Str::slug($sector->name)) === $key);
|
||||
if ($exists) {
|
||||
continue;
|
||||
}
|
||||
$slug = Str::slug($name);
|
||||
if (Sector::withTrashed()->where('slug', $slug)->exists()) {
|
||||
$slug .= '-especifica';
|
||||
}
|
||||
Sector::create(['name' => $name, 'slug' => $slug, 'is_active' => true, 'sort_order' => 100, 'published_at' => now()]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user