id(); $table->foreignId('source_id')->constrained()->cascadeOnDelete(); // PostgreSQL : JSONB (binary JSON, indexable par GIN) // MySQL : JSON if ($isPgsql) { $table->jsonb('data'); } else { $table->json('data'); } $table->foreignId('created_by')->constrained('users')->restrictOnDelete(); $table->foreignId('updated_by')->constrained('users')->restrictOnDelete(); $table->timestamps(); }); // ── Colonnes générées stockées (syntaxe différente selon le SGBD) ────── $nomExpr = DbCompat::generatedJsonCol('nom'); $prenomExpr = DbCompat::generatedJsonCol('prenom'); $dateEvtExpr = DbCompat::generatedJsonNestedCol('date_evenement.valeur'); if ($isPgsql) { DB::statement("ALTER TABLE releves ADD COLUMN nom TEXT GENERATED ALWAYS AS ({$nomExpr}) STORED"); DB::statement("ALTER TABLE releves ADD COLUMN prenom TEXT GENERATED ALWAYS AS ({$prenomExpr}) STORED"); DB::statement("ALTER TABLE releves ADD COLUMN date_evenement TEXT GENERATED ALWAYS AS ({$dateEvtExpr}) STORED"); } else { DB::statement("ALTER TABLE releves ADD COLUMN nom VARCHAR(255) GENERATED ALWAYS AS ({$nomExpr}) STORED"); DB::statement("ALTER TABLE releves ADD COLUMN prenom VARCHAR(255) GENERATED ALWAYS AS ({$prenomExpr}) STORED"); DB::statement("ALTER TABLE releves ADD COLUMN date_evenement VARCHAR(255) GENERATED ALWAYS AS ({$dateEvtExpr}) STORED"); } // ── Index B-tree sur les colonnes générées ─────────────────────────── DB::statement('CREATE INDEX releves_nom_idx ON releves (nom)'); DB::statement('CREATE INDEX releves_prenom_idx ON releves (prenom)'); DB::statement('CREATE INDEX releves_date_evenement_idx ON releves (date_evenement)'); // ── Index GIN sur le JSON complet (PostgreSQL uniquement) ───────────── if ($isPgsql) { DB::statement('CREATE INDEX releves_data_gin_idx ON releves USING gin (data)'); } } public function down(): void { Schema::dropIfExists('releves'); } };