|
|
|
@ -4,6 +4,9 @@ namespace App\Models; |
|
|
|
|
|
|
|
|
|
use App\Models\Concerns\Reportable; |
|
|
|
|
use App\Tables\Changeset; |
|
|
|
|
use App\Tables\Column; |
|
|
|
|
use Illuminate\Database\Eloquent\Builder; |
|
|
|
|
use Illuminate\Support\Facades\DB; |
|
|
|
|
use MightyPork\Exceptions\NotApplicableException; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@ -16,7 +19,7 @@ use MightyPork\Exceptions\NotApplicableException; |
|
|
|
|
* @property int $revision_id |
|
|
|
|
* @property int $author_id |
|
|
|
|
* @property string $note |
|
|
|
|
* @property Proposal $changes - JSONB |
|
|
|
|
* @property Changeset $changeset - JSONB |
|
|
|
|
* @property-read User $author |
|
|
|
|
* @property-read Table $table |
|
|
|
|
* @property-read Revision $revision |
|
|
|
@ -46,17 +49,30 @@ class Proposal extends BaseModel |
|
|
|
|
return $this->belongsTo(Table::class); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public function getChangesAttribute($value) |
|
|
|
|
public function scopeUnmerged(Builder $query, Table $table) |
|
|
|
|
{ |
|
|
|
|
$changeset = Changeset::fromObject(fromJSON($value)); |
|
|
|
|
return $query->whereRaw(' |
|
|
|
|
"id" NOT IN |
|
|
|
|
(SELECT "proposal_id" FROM "revisions" |
|
|
|
|
LEFT JOIN "table_revision_pivot" |
|
|
|
|
ON "revisions"."id" = "table_revision_pivot"."revision_id" |
|
|
|
|
WHERE "table_revision_pivot"."table_id" = ?)', |
|
|
|
|
[ |
|
|
|
|
$table->getKey() |
|
|
|
|
]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public function getChangesetAttribute() |
|
|
|
|
{ |
|
|
|
|
$changeset = Changeset::fromObject(fromJSON($this->attributes['changes'], true)); |
|
|
|
|
$changeset->revision = $this->revision; |
|
|
|
|
$changeset->table = $this->table; |
|
|
|
|
$changeset->table = $this->getAttribute('table'); |
|
|
|
|
$changeset->note = $this->note; |
|
|
|
|
|
|
|
|
|
return $changeset; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public function setChangesAttribute($value) |
|
|
|
|
public function setChangesetAttribute($value) |
|
|
|
|
{ |
|
|
|
|
if ($value instanceof Changeset) { |
|
|
|
|
$this->attributes['changes'] = toJSON($value->toObject()); |
|
|
|
@ -98,10 +114,96 @@ class Proposal extends BaseModel |
|
|
|
|
// relations |
|
|
|
|
'table_id' => $changeset->table->getKey(), |
|
|
|
|
'revision_id' => $changeset->revision->getKey(), |
|
|
|
|
'author_id' => \Auth::user()->getKey(), |
|
|
|
|
'author_id' => \user()->getKey(), |
|
|
|
|
// the proposal info |
|
|
|
|
'note' => $changeset->note, |
|
|
|
|
'changes' => $changeset->toObject(), |
|
|
|
|
'changeset' => $changeset, // this is without a note |
|
|
|
|
]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Accept the proposed changes: create a new revision based on the parent revision |
|
|
|
|
* and changes described in this Proposal, and link it to the table. |
|
|
|
|
*/ |
|
|
|
|
public function createRevision() |
|
|
|
|
{ |
|
|
|
|
DB::transaction(function () { |
|
|
|
|
$changeset = $this->changeset; |
|
|
|
|
|
|
|
|
|
$columns = $changeset->fetchAndTransformColumns(); |
|
|
|
|
|
|
|
|
|
$newRevision = new Revision([ |
|
|
|
|
'ancestor_id' => $changeset->revision->getKey(), |
|
|
|
|
'proposal_id' => $this->getKey(), |
|
|
|
|
'note' => $changeset->note, |
|
|
|
|
'row_count' => 0, // Will be set later when we are sure about the row count |
|
|
|
|
'columns' => array_map(function(Column $c) { |
|
|
|
|
return $c->toArray(false); |
|
|
|
|
}, $columns), |
|
|
|
|
]); |
|
|
|
|
|
|
|
|
|
$newRevision->save(); // this gives it an ID, needed to associate rows |
|
|
|
|
|
|
|
|
|
// --- Copy over rows that are left unchanged --- |
|
|
|
|
// ...this directly works with the pivot |
|
|
|
|
$removedRowIds = (array)($changeset->removedRows ?? []); |
|
|
|
|
$changedRowIds = array_keys((array)($changeset->rowUpdates ?? [])); |
|
|
|
|
$excludedGRIDs = array_merge($removedRowIds, $changedRowIds); |
|
|
|
|
|
|
|
|
|
$excluded_ids = []; |
|
|
|
|
|
|
|
|
|
if ($excludedGRIDs) { |
|
|
|
|
$questionmarks = str_repeat('?,', count($excludedGRIDs) - 1) . '?'; |
|
|
|
|
$excluded_ids = $changeset->revision->rows()->whereRaw("data->'_id' IN ($questionmarks)", $excludedGRIDs) |
|
|
|
|
->get(['id'])->pluck('id')->toArray(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$query = ' |
|
|
|
|
INSERT INTO revision_row_pivot |
|
|
|
|
SELECT ? as revision_id, row_id FROM revision_row_pivot |
|
|
|
|
WHERE revision_id = ?'; |
|
|
|
|
$subs = [ |
|
|
|
|
$newRevision->getKey(), |
|
|
|
|
$changeset->revision->getKey() |
|
|
|
|
]; |
|
|
|
|
if ($excluded_ids) { |
|
|
|
|
$questionmarks = str_repeat('?,', count($excluded_ids) - 1) . '?'; |
|
|
|
|
$query .= ' AND row_id NOT IN (' . $questionmarks . ')'; |
|
|
|
|
$subs = array_merge($subs, $excluded_ids); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
DB::statement($query, $subs); |
|
|
|
|
|
|
|
|
|
// --- Insert modified rows --- |
|
|
|
|
if ($changeset->rowUpdates) { |
|
|
|
|
$ids = array_keys($changeset->rowUpdates); |
|
|
|
|
$questionmarks = str_repeat('?,', count($ids) - 1) . '?'; |
|
|
|
|
|
|
|
|
|
$toChange = $changeset->revision->rows()->whereRaw("data->'_id' IN ($questionmarks)", $ids)->get(); |
|
|
|
|
|
|
|
|
|
$updateData = []; |
|
|
|
|
foreach ($toChange as $row) { |
|
|
|
|
$updateData[] = new Row([ |
|
|
|
|
'data' => $changeset->transformRow($row->data, false), |
|
|
|
|
]); |
|
|
|
|
} |
|
|
|
|
$newRevision->rows()->saveMany($updateData); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// --- Insert new rows --- |
|
|
|
|
if ($changeset->newRows) { |
|
|
|
|
$newRowData = []; |
|
|
|
|
foreach ($changeset->newRows as $newRow) { |
|
|
|
|
$newRowData[] = new Row(['data' => $newRow]); |
|
|
|
|
} |
|
|
|
|
$newRevision->rows()->saveMany($newRowData); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$newRevision->update(['row_count' => $newRevision->rows()->count()]); |
|
|
|
|
|
|
|
|
|
// --- Attach this revision to the table --- |
|
|
|
|
$changeset->table->revisions()->save($newRevision); |
|
|
|
|
$changeset->table->update(['revision_id' => $newRevision->getKey()]); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|