provincias
tests / ci (push) Canceled after 0s

This commit is contained in:
2026-09-29 14:14:06 +02:00
parent e780e67e98
commit 67dad461d9
35 changed files with 1046 additions and 42 deletions
@@ -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');
}
};
+30
View File
@@ -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()]);
}
});
}
}