Start unifying schema types

Schemas per se are type agnostic, isLookup property is removed. Data is stored and accessed differently based on how it is entered and retrieved.

The crucial change is introduction of the composite key of pid and rid. Previous page data utilizes rid = 0 to differentiate itself. Other types, notably lookup, have autoincrementing rid.

Database migration is not implemented yet.
This commit is contained in:
Anna Dabrowska
2020-03-11 17:12:54 +01:00
parent 700f943db9
commit 0ceefd5c55
28 changed files with 192 additions and 205 deletions

View File

@ -54,10 +54,11 @@ class schemaBuilder_struct_test extends StructTest {
$tableSQL = $this->sqlite->res2single($res);
$this->sqlite->res_close($res);
$expected_tableSQL = "CREATE TABLE data_testtable (
pid NOT NULL,
rev INTEGER NOT NULL,
pid TEXT DEFAULT NULL,
rid INTEGER,
rev INTEGER,
latest BOOLEAN NOT NULL DEFAULT 0, col1 DEFAULT '', col2 DEFAULT '',
PRIMARY KEY(pid, rev)
PRIMARY KEY(pid, rid, rev)
)";
$res = $this->sqlite->query("SELECT * FROM types");

View File

@ -14,11 +14,12 @@ abstract class AccessTable extends meta\AccessTable {
* @return meta\AccessTableLookup|AccessTableData
*/
public static function bySchema(Schema $schema, $pid, $ts = 0) {
if($schema->isLookup()) {
return new meta\AccessTableLookup($schema, $pid, $ts); // FIXME not mocked, yet
} else {
return new AccessTableData($schema, $pid, $ts);
}
// FIXME will we still need that?
// if($schema->isLookup()) {
// return new meta\AccessTableLookup($schema, $pid, $ts); // FIXME not mocked, yet
// } else {
// }
return new AccessTableData($schema, $pid, $ts);
}
public static function byTableName($tablename, $pid, $ts = 0) {

View File

@ -116,7 +116,7 @@ class action_plugin_struct_inline extends DokuWiki_Action_Plugin {
throw new StructException('inline save error: init');
}
self::checkCSRF();
if(!$this->schemadata->getSchema()->isLookup()) {
if(!$this->schemadata->getRid()) {
$this->checkPage();
$assignments = Assignments::getInstance();
$tables = $assignments->getPageAssignments($this->pid, true);
@ -140,7 +140,7 @@ class action_plugin_struct_inline extends DokuWiki_Action_Plugin {
$tosave[$this->column->getLabel()] = $value;
// save
if($this->schemadata->getSchema()->isLookup()) {
if($this->schemadata->getRid() && !$this->schemadata->getPid()) {
$revision = 0;
} else {
$revision = helper_plugin_struct::createPageRevision($this->pid, 'inline edit');
@ -151,7 +151,7 @@ class action_plugin_struct_inline extends DokuWiki_Action_Plugin {
if(!$this->schemadata->saveData($tosave)) {
throw new StructException('saving failed');
}
if(!$this->schemadata->getSchema()->isLookup()) {
if(!$this->schemadata->getRid()) {
// make sure this schema is assigned
/** @noinspection PhpUndefinedVariableInspection */
$assignments->assignPageSchema(

View File

@ -85,16 +85,16 @@ class action_plugin_struct_lookup extends DokuWiki_Action_Plugin
{
global $INPUT;
$tablename = $INPUT->str('schema');
$pid = $INPUT->int('pid');
if (!$pid) {
throw new StructException('No pid given');
$rid = $INPUT->int('rid');
if (!$rid) {
throw new StructException('No row id given');
}
if (!$tablename) {
throw new StructException('No schema given');
}
action_plugin_struct_inline::checkCSRF();
$schemadata = AccessTable::byTableName($tablename, $pid);
$schemadata = AccessTable::byTableName($tablename, 0, 0, $rid);
if (!$schemadata->getSchema()->isEditable()) {
throw new StructException('lookup delete error: no permission for schema');
}
@ -118,9 +118,9 @@ class action_plugin_struct_lookup extends DokuWiki_Action_Plugin
$helper = plugin_load('helper', 'struct');
$helper->saveLookupData($access, $data);
$pid = $access->getPid();
$rid = $access->getRid();
$config = json_decode($INPUT->str('searchconf'), true);
$config['filter'] = array(array('%rowid%', '=', $pid, 'AND'));
$config['filter'] = array(array('%rowid%', '=', $rid, 'AND'));
$lookup = new LookupTable(
'', // current page doesn't matter
'xhtml',

View File

@ -185,9 +185,11 @@ class action_plugin_struct_move extends DokuWiki_Action_Plugin {
$tconf = $col->getType()->getConfig();
$ref = new Schema($tconf['schema']);
if(!$ref->getId()) return; // this schema does not exist
if($ref->isLookup()) return; // a lookup is referenced, nothing to do
// FIXME does this make sense at all? it's always a lookup, isn't it?
if(!$ref->getTimeStamp()) return; // a lookup is referenced, nothing to do
// var_dump($ref) && die();
$this->updateColumnID($schema, $col, $old, $new);
// $this->updateColumnID($schema, $col, $old, $new);
}
}

View File

@ -137,7 +137,7 @@ class admin_plugin_struct_assignments extends DokuWiki_Admin_Plugin {
echo '<td><input type="text" name="assignment[assign]" /></td>';
echo '<td>';
echo '<select name="assignment[tbl]">';
foreach(Schema::getAll('page') as $table) {
foreach(Schema::getAll() as $table) {
echo '<option value="' . hsc($table) . '">' . hsc($table) . '</option>';
}
echo '</select>';

View File

@ -147,15 +147,10 @@ class admin_plugin_struct_schemas extends DokuWiki_Admin_Plugin {
$table = Schema::cleanTableName($INPUT->str('table'));
if($table) {
$schema = new Schema($table, 0, $INPUT->bool('lookup'));
if($schema->isLookup()) {
$hl = 'edithl lookup';
} else {
$hl = 'edithl page';
}
$schema = new Schema($table, 0);
echo $this->locale_xhtml('editor_edit');
echo '<h2>' . sprintf($this->getLang($hl), hsc($table)) . '</h2>';
echo '<h2>' . sprintf($this->getLang('edithl'), hsc($table)) . '</h2>';
echo '<ul class="tabs" id="plugin__struct_tabs">';
/** @noinspection HtmlUnknownAnchorTarget */
@ -189,7 +184,6 @@ class admin_plugin_struct_schemas extends DokuWiki_Admin_Plugin {
$form->setHiddenField('do', 'admin');
$form->setHiddenField('page', 'struct_schemas');
$form->setHiddenField('table', $schema->getTable());
$form->setHiddenField('lookup', $schema->isLookup());
$form->addFieldsetOpen($this->getLang('export'));
$form->addButton('export', $this->getLang('btn_export'));
@ -254,8 +248,6 @@ class admin_plugin_struct_schemas extends DokuWiki_Admin_Plugin {
$form->setHiddenField('do', 'admin');
$form->setHiddenField('page', 'struct_schemas');
$form->addTextInput('table', $this->getLang('schemaname'));
$form->addRadioButton('lookup', $this->getLang('page schema'))->val('0')->attr('checked', 'checked');
$form->addRadioButton('lookup', $this->getLang('lookup schema'))->val('1');
$form->addButton('', $this->getLang('save'));
$form->addHTML('<p>' . $this->getLang('createhint') . '</p>'); // FIXME is that true? we probably could
$form->addFieldsetClose();
@ -286,9 +278,8 @@ class admin_plugin_struct_schemas extends DokuWiki_Admin_Plugin {
);
$toc[] = html_mktocitem($slink, $this->getLang('menu'), 0, '');
$tables = Schema::getAll('page');
$tables = Schema::getAll();
if($tables) {
$toc[] = html_mktocitem($slink, $this->getLang('page schema'), 1, '');
foreach($tables as $table) {
$link = wl(
$ID, array(
@ -298,23 +289,7 @@ class admin_plugin_struct_schemas extends DokuWiki_Admin_Plugin {
)
);
$toc[] = html_mktocitem($link, hsc($table), 2, '');
}
}
$tables = Schema::getAll('lookup');
if($tables) {
$toc[] = html_mktocitem($slink, $this->getLang('lookup schema'), 1, '');
foreach($tables as $table) {
$link = wl(
$ID, array(
'do' => 'admin',
'page' => 'struct_schemas',
'table' => $table
)
);
$toc[] = html_mktocitem($link, hsc($table), 2, '');
$toc[] = html_mktocitem($link, hsc($table), 1, '');
}
}

3
db/update0016.sql Normal file
View File

@ -0,0 +1,3 @@
-- this migration is handled in action/migration.php in migration16()
--
-- unifies page and lookup schemas

View File

@ -109,10 +109,10 @@ class helper_plugin_struct extends DokuWiki_Plugin {
/**
* Save data row for a lookup schema
*
* @param AccessTableLookup $access the table into which to save the data
* @param AccessTable $access the table into which to save the data
* @param array $data data to be saved in the form of [columnName => 'data']
*/
public function saveLookupData(AccessTableLookup $access, $data)
public function saveLookupData(AccessTable $access, $data)
{
if(!$access->getSchema()->isEditable()) {
throw new StructException('lookup save error: no permission for schema');

View File

@ -10,6 +10,7 @@ $lang['menu_assignments'] = 'Struct Přiřazení schémat';
$lang['headline'] = 'Strukturovaná data';
$lang['page schema'] = '\'Stránkové schéma:';
$lang['lookup schema'] = 'Vyhledávací schéma:';
$lang['edithl'] = 'Editování schematu <i>%s</i>';
$lang['edithl page'] = 'Editování stránkového schematu <i>%s</i>';
$lang['edithl lookup'] = 'Editování vyhledávacího schematu <i>%s</i>';
$lang['create'] = 'Vytvořit nové schéma';

View File

@ -13,8 +13,7 @@ $lang['menu_assignments'] = 'Struct Schema Zuweisungen';
$lang['headline'] = 'Strukturierte Daten';
$lang['page schema'] = 'Seiten Schema';
$lang['lookup schema'] = 'Lookup Schema';
$lang['edithl page'] = 'Bearbeitung Seiten Schema <i>%s</i>';
$lang['edithl lookup'] = 'Bearbeitung Lookup Schema <i>%s</i>';
$lang['edithl'] = 'Bearbeitung von Schema <i>%s</i>';
$lang['create'] = 'Neues Schema anlegen';
$lang['schemaname'] = 'Schema-Name:';
$lang['save'] = 'Speichern';

View File

@ -13,8 +13,7 @@ $lang['headline'] = 'Structured Data';
$lang['page schema'] = 'Page Schema:';
$lang['lookup schema'] = 'Lookup Schema:';
$lang['edithl page'] = 'Editing Page Schema <i>%s</i>';
$lang['edithl lookup'] = 'Editing Lookup Schema <i>%s</i>';
$lang['edithl'] = 'Editing schema <i>%s</i>';
$lang['create'] = 'Create new Schema';
$lang['schemaname'] = 'Schema Name:';
$lang['save'] = 'Save';

View File

@ -17,8 +17,7 @@ $lang['menu_assignments'] = 'Struct - Affectation de schémas';
$lang['headline'] = 'Données structurées';
$lang['page schema'] = 'Schéma de page';
$lang['lookup schema'] = 'Schéma de consultation';
$lang['edithl page'] = 'Édition du schéma de page <i>%s</i>';
$lang['edithl lookup'] = 'Édition du schéma de consultation <i>%s</i>';
$lang['edithl'] = 'Édition du schéma <i>%s</i>';
$lang['create'] = 'Créer un nouveau schéma';
$lang['schemaname'] = 'Nom du schéma :';
$lang['save'] = 'Sauvegarder';

View File

@ -7,6 +7,7 @@ abstract class AccessTable {
/** @var Schema */
protected $schema;
protected $pid;
protected $rid;
protected $labels = array();
protected $ts = 0;
/** @var \helper_plugin_sqlite */
@ -21,14 +22,14 @@ abstract class AccessTable {
* @param Schema $schema schema to load
* @param string|int $pid Page or row id to access
* @param int $ts Time at which the data should be read or written, 0 for now
* @param int $rid
* @return AccessTableData|AccessTableLookup
*/
public static function bySchema(Schema $schema, $pid, $ts = 0) {
if($schema->isLookup()) {
return new AccessTableLookup($schema, $pid, $ts);
} else {
return new AccessTableData($schema, $pid, $ts);
public static function bySchema(Schema $schema, $pid, $ts = 0, $rid = 0) {
if (!$pid && $ts === 0) {
return new AccessTableLookup($schema, $pid, $ts, $rid);
}
return new AccessTableData($schema, $pid, $ts, $rid);
}
/**
@ -37,11 +38,12 @@ abstract class AccessTable {
* @param string $tablename schema to load
* @param string|int $pid Page or row id to access
* @param int $ts Time at which the data should be read or written, 0 for now
* @param int $rid
* @return AccessTableData|AccessTableLookup
*/
public static function byTableName($tablename, $pid, $ts = 0) {
public static function byTableName($tablename, $pid, $ts = 0, $rid = 0) {
$schema = new Schema($tablename, $ts);
return self::bySchema($schema, $pid, $ts);
return self::bySchema($schema, $pid, $ts, $rid);
}
/**
@ -50,8 +52,9 @@ abstract class AccessTable {
* @param Schema $schema The schema valid at $ts
* @param string|int $pid
* @param int $ts Time at which the data should be read or written, 0 for now
* @param int $rid Row id: 0 for pages, autoincremented for other types
*/
public function __construct(Schema $schema, $pid, $ts = 0) {
public function __construct(Schema $schema, $pid, $ts = 0, $rid = 0) {
/** @var \helper_plugin_struct_db $helper */
$helper = plugin_load('helper', 'struct_db');
$this->sqlite = $helper->getDB();
@ -62,6 +65,7 @@ abstract class AccessTable {
$this->schema = $schema;
$this->pid = $pid;
$this->rid = $rid;
$this->setTimestamp($ts);
foreach($this->schema->getColumns() as $col) {
$this->labels[$col->getColref()] = $col->getType()->getLabel();
@ -86,6 +90,15 @@ abstract class AccessTable {
return $this->pid;
}
/**
* The current rid
*
* @return int|string
*/
public function getRid() {
return $this->rid;
}
/**
* Should remove the current data, by either deleting or ovewriting it
*

View File

@ -11,19 +11,7 @@ namespace dokuwiki\plugin\struct\meta;
*/
class AccessTableData extends AccessTable {
/**
* AccessTableData constructor
*
* @param Schema $schema Which schema to access
* @param string $pid The page of which the data is for
* @param int $ts Time at which the data should be read or written, 0 for now
*/
public function __construct(Schema $schema, $pid, $ts = 0) {
parent::__construct($schema, $pid, $ts);
if($this->schema->isLookup()) {
throw new StructException('wrong schema type. use factory methods!');
}
}
const DEFAULT_PAGE_RID = 0;
/**
* adds an empty data set for this schema and page
@ -64,9 +52,10 @@ class AccessTableData extends AccessTable {
$colrefs = array_flip($this->labels);
$now = $this->ts;
$opt = array($this->pid, $now, 1);
$opt = array(self::DEFAULT_PAGE_RID, $this->pid, $now, 1);
$multiopts = array();
$singlecols = 'pid, rev, latest';
$singlecols = 'rid, pid, rev, latest';
foreach ($data as $colname => $value) {
if(!isset($colrefs[$colname])) {
throw new StructException("Unknown column %s in schema.", hsc($colname));
@ -87,9 +76,11 @@ class AccessTableData extends AccessTable {
$opt[] = $value;
}
}
$singlesql = "INSERT INTO $stable ($singlecols) VALUES (" . trim(str_repeat('?,',count($opt)),',') . ")";
$singlesql = "INSERT INTO $stable ($singlecols) VALUES (" . trim(str_repeat('?,',count($opt)),',') . ');';
/** @noinspection SqlResolve */
$multisql = "INSERT INTO $mtable (latest, rev, pid, colref, row, value) VALUES (?, ?,?,?,?,?)";
$multisql = "INSERT INTO $mtable (latest, rev, pid, rid, colref, row, value) VALUES (?,?,?,?,?,?)";
$this->sqlite->query('BEGIN TRANSACTION');
@ -105,7 +96,7 @@ class AccessTableData extends AccessTable {
// insert multi values
foreach ($multiopts as $multiopt) {
$multiopt = array_merge(array(1, $now, $this->pid,), $multiopt);
$multiopt = array_merge(array(1, $now, $this->pid, self::DEFAULT_PAGE_RID), $multiopt);
$ok = $ok && $this->sqlite->query($multisql, $multiopt);
}

View File

@ -17,24 +17,25 @@ class AccessTableLookup extends AccessTable {
* @param Schema $schema Which schema to access
* @param int $pid the row identifier (0 for new row)
* @param int $ts Time at which the data should be read or written, 0 for now
* @param int $rid
*/
public function __construct(Schema $schema, $pid = 0, $ts = 0) {
parent::__construct($schema, $pid, $ts);
if(!$this->schema->isLookup()) {
throw new StructException('wrong schema type. use factory methods!');
}
public function __construct(Schema $schema, $pid = 0, $ts = 0, $rid = 0) {
parent::__construct($schema, $pid, $ts, $rid);
// if(!$this->schema->isLookup()) {
// throw new StructException('wrong schema type. use factory methods!');
// }
}
/**
* Remove the current data
*/
public function clearData() {
if(!$this->pid) return; // no data
if(!$this->rid) return; // no data
/** @noinspection SqlResolve */
$sql = "DELETE FROM ? WHERE pid = ?";
$this->sqlite->query($sql, 'data_'.$this->schema->getTable(), $this->pid);
$this->sqlite->query($sql, 'multi_'.$this->schema->getTable(), $this->pid);
$sql = 'DELETE FROM ? WHERE rid = ?';
$this->sqlite->query($sql, 'data_'.$this->schema->getTable(), $this->rid);
$this->sqlite->query($sql, 'multi_'.$this->schema->getTable(), $this->rid);
}
/**
@ -58,13 +59,8 @@ class AccessTableLookup extends AccessTable {
if($isempty) return false;
$singlecols = array();
$opt = array();
if($this->pid) {
$singlecols[] = 'pid';
$opt[] = $this->pid;
}
$singlecols = ['rev', 'latest'];
$opt = [0, 1];
$colrefs = array_flip($this->labels);
$multiopts = array();
@ -88,9 +84,13 @@ class AccessTableLookup extends AccessTable {
$opt[] = $value;
}
}
$singlesql = "REPLACE INTO $stable (" . join(',', $singlecols) . ") VALUES (" . trim(str_repeat('?,', count($opt)), ',') . ")";
$ridSingle = "(SELECT (COALESCE(MAX(rid), 0 ) + 1) FROM $stable)";
$ridMulti = "(SELECT (COALESCE(MAX(rid), 0 ) + 1) FROM $mtable)";
$singlesql = "REPLACE INTO $stable (pid, rid, " . join(',', $singlecols) . ") VALUES (NULL, $ridSingle, " . trim(str_repeat('?,', count($opt)), ',') . ")";
/** @noinspection SqlResolve */
$multisql = "REPLACE INTO $mtable (pid, colref, row, value) VALUES (?,?,?,?)";
$multisql = "REPLACE INTO $mtable (pid, rid, colref, row, value) VALUES (NULL, $ridMulti, ?,?,?)";
$this->sqlite->query('BEGIN TRANSACTION');
$ok = true;
@ -98,17 +98,17 @@ class AccessTableLookup extends AccessTable {
// insert single values
$ok = $ok && $this->sqlite->query($singlesql, $opt);
// get new pid if this is a new insert
if($ok && !$this->pid) {
// get new rid if this is a new insert
if($ok && !$this->rid) {
$res = $this->sqlite->query('SELECT last_insert_rowid()');
$this->pid = $this->sqlite->res2single($res);
$this->rid = $this->sqlite->res2single($res);
$this->sqlite->res_close($res);
if(!$this->pid) $ok = false;
if(!$this->rid) $ok = false;
}
// insert multi values
if($ok) foreach($multiopts as $multiopt) {
$multiopt = array_merge(array($this->pid,), $multiopt);
$multiopt = array_merge(array($this->rid,), $multiopt);
$ok = $ok && $this->sqlite->query($multisql, $multiopt);
}

View File

@ -45,6 +45,7 @@ class AggregationTable {
* @var string[] the result PIDs for each row
*/
protected $resultPIDs;
protected $resultRids;
/**
* @var array for summing up columns
@ -83,6 +84,7 @@ class AggregationTable {
$this->result = $this->searchConfig->execute();
$this->resultCount = $this->searchConfig->getCount();
$this->resultPIDs = $this->searchConfig->getPids();
$this->resultRids = $this->searchConfig->getRids();
$this->helper = plugin_load('helper', 'struct_config');
}
@ -360,8 +362,9 @@ class AggregationTable {
// add data attribute for inline edit
if($this->mode == 'xhtml') {
$pid = $this->resultPIDs[$rownum];
$rid = $this->resultRids[$rownum];
$this->renderer->doc = substr(rtrim($this->renderer->doc), 0, -1); // remove closing '>'
$this->renderer->doc .= ' data-pid="' . hsc($pid) . '">';
$this->renderer->doc .= ' data-pid="' . hsc($pid) . '" data-rid="' . hsc($rid) . '">';
}
// row number column

View File

@ -17,11 +17,11 @@ class CSVPageImporter extends CSVImporter {
* @param string $table
* @param string $file
*/
public function __construct($table, $file) {
parent::__construct($table, $file);
if($this->schema->isLookup()) throw new StructException($table.' is not a page schema');
}
// public function __construct($table, $file) {
// parent::__construct($table, $file);
//
// if($this->schema->isLookup()) throw new StructException($table.' is not a page schema');
// }
/**
* Import page schema only when the pid header is present.

View File

@ -66,15 +66,4 @@ class LookupTable extends AggregationTable {
return $this->renderer->doc;
}
/**
* @inheritDoc
*/
public function render() {
if(!$this->searchConfig->getSchemas()[0]->isLookup()) {
msg($this->helper->getLang('no_lookup_for_page'), -1);
return;
}
parent::render();
}
}

View File

@ -26,6 +26,14 @@ class RowColumn extends PageColumn {
return '%rowid%';
}
/**
* @param bool $enforceSingleColumn ignored
* @return string
*/
public function getColName($enforceSingleColumn = true) {
return 'rid';
}
/**
* @return string preconfigured label
*/

View File

@ -32,9 +32,6 @@ class Schema {
/** @var string name of the associated table */
protected $table = '';
/** @var bool is this a lookup schema? */
protected $islookup = false;
/**
* @var string the current checksum of this schema
*/
@ -60,9 +57,8 @@ class Schema {
*
* @param string $table The table this schema is for
* @param int $ts The timestamp for when this schema was valid, 0 for current
* @param bool $islookup only used when creating a new schema, makes the new schema a lookup
*/
public function __construct($table, $ts = 0, $islookup = false) {
public function __construct($table, $ts = 0) {
$baseconfig = array('allowed editors' => '');
/** @var \helper_plugin_struct_db $helper */
@ -99,11 +95,8 @@ class Schema {
$this->id = $result['id'];
$this->user = $result['user'];
$this->chksum = isset($result['chksum']) ? $result['chksum'] : '';
$this->islookup = $result['islookup'];
$this->ts = $result['ts'];
$config = json_decode($result['config'], true);
} else {
$this->islookup = $islookup;
}
$this->sqlite->res_close($res);
$this->config = array_merge($baseconfig, $config);
@ -225,7 +218,7 @@ class Schema {
$this->sqlite->query($sql, $this->table);
$sql = "SELECT T.id
FROM types T, schema_cols SC, schemas S
FROM types T, schema_cols SC, schemas S
WHERE T.id = SC.tid
AND SC.sid = S.id
AND S.tbl = ?";
@ -233,7 +226,7 @@ class Schema {
$this->sqlite->query($sql, $this->table);
$sql = "SELECT id
FROM schemas
FROM schemas
WHERE tbl = ?";
$sql = "DELETE FROM schema_cols WHERE sid IN ($sql)";
$this->sqlite->query($sql, $this->table);
@ -288,13 +281,6 @@ class Schema {
return $this->ts;
}
/**
* @return bool is this a lookup schema?
*/
public function isLookup() {
return $this->islookup;
}
/**
* @return string
*/

View File

@ -57,7 +57,7 @@ class SchemaBuilder {
public function __construct($table, $data) {
$this->table = $table;
$this->data = $data;
$this->oldschema = new Schema($table, 0, $data['islookup']);
$this->oldschema = new Schema($table, 0);
$this->helper = plugin_load('helper', 'struct_db');
$this->sqlite = $this->helper->getDB();
@ -78,11 +78,7 @@ class SchemaBuilder {
$ok = true;
// create the data table if new schema
if(!$this->oldschema->getId()) {
if($this->oldschema->isLookup()) {
$ok = $this->newLookupTable();
} else {
$ok = $this->newDataTable();
}
$ok = $this->newDataTable();
}
// create a new schema
@ -149,7 +145,8 @@ class SchemaBuilder {
/** @noinspection SqlResolve */
$sql = "INSERT INTO schemas (tbl, ts, islookup, user, config) VALUES (?, ?, ?, ?, ?)";
$this->sqlite->query($sql, $this->table, $this->time, (int) $this->oldschema->isLookup(), $this->user, $config);
// FIXME magic 0 for islookup
$this->sqlite->query($sql, $this->table, $this->time, 0, $this->user, $config);
$res = $this->sqlite->query('SELECT last_insert_rowid()');
$this->newschemaid = $this->sqlite->res2single($res);
$this->sqlite->res_close($res);
@ -208,6 +205,7 @@ class SchemaBuilder {
/**
* Write the latest value from an entry in a data_ table to the corresponding multi_table
* FIXME handle rid
*
* @param string $table
* @param int $colref
@ -302,57 +300,27 @@ class SchemaBuilder {
$ok = true;
$tbl = 'data_' . $this->table;
// FIXME default latest in data table is 1 for lookups, 0 for pages
// FIXME because lookup data is never versioned?
$sql = "CREATE TABLE $tbl (
pid NOT NULL,
rev INTEGER NOT NULL,
pid TEXT DEFAULT NULL,
rid INTEGER,
rev INTEGER,
latest BOOLEAN NOT NULL DEFAULT 0,
PRIMARY KEY(pid, rev)
PRIMARY KEY(pid, rid, rev)
)";
$ok = $ok && (bool) $this->sqlite->query($sql);
$tbl = 'multi_' . $this->table;
$sql = "CREATE TABLE $tbl (
colref INTEGER NOT NULL,
pid NOT NULL,
rev INTEGER NOT NULL,
pid TEXT,
rid INTEGER,
rev INTEGER,
latest INTEGER NOT NULL DEFAULT 0,
row INTEGER NOT NULL,
value,
PRIMARY KEY(colref, pid, rev, row)
);";
$ok = $ok && (bool) $this->sqlite->query($sql);
return $ok;
}
/**
* Creates a new lookup table with no columns
*
* This is basically the same as @see newDataTable() but sets
* different primary keys and types
*
* @return bool
*/
protected function newLookupTable() {
$ok = true;
$tbl = 'data_' . $this->table;
$sql = "CREATE TABLE $tbl (
pid INTEGER PRIMARY KEY,
rev INTEGER NOT NULL DEFAULT 0,
latest BOOLEAN NOT NULL DEFAULT 1
)";
$ok = $ok && (bool) $this->sqlite->query($sql);
$tbl = 'multi_' . $this->table;
$sql = "CREATE TABLE $tbl (
colref INTEGER NOT NULL,
pid INTEGER NOT NULL,
rev INTEGER NOT NULL DEFAULT 0,
latest INTEGER NOT NULL DEFAULT 0,
row INTEGER NOT NULL,
value,
PRIMARY KEY(colref, pid, row)
PRIMARY KEY(colref, pid, rid, rev, row)
);";
$ok = $ok && (bool) $this->sqlite->query($sql);

View File

@ -45,7 +45,6 @@ class SchemaEditor {
$form->setHiddenField('page', 'struct_schemas');
$form->setHiddenField('table', $this->schema->getTable());
$form->setHiddenField('schema[id]', $this->schema->getId());
$form->setHiddenField('schema[islookup]', $this->schema->isLookup());
$form->addHTML('<table class="inline">');
$form->addHTML("<tr>

View File

@ -51,6 +51,8 @@ class Search {
protected $count = -1;
/** @var string[] the PIDs of the result rows */
protected $result_pids = null;
/** @var array the row ids of the result rows */
protected $result_rids = [];
/**
* Search constructor.
@ -75,14 +77,15 @@ class Search {
throw new StructException('schema missing', $table);
}
if($this->schemas &&
(
$schema->isLookup() ||
reset($this->schemas)->isLookup()
)
) {
throw new StructException('nolookupmix');
}
// FIXME is the mixing still relevant?
// if($this->schemas &&
// (
// $schema->isLookup() ||
// reset($this->schemas)->isLookup()
// )
// ) {
// throw new StructException('nolookupmix');
// }
$this->schemas[$schema->getTable()] = $schema;
if($alias) $this->aliases[$alias] = $schema->getTable();
@ -265,6 +268,18 @@ class Search {
return $this->result_pids;
}
/**
* Returns the rid associated with each result row
*
* Important: this may only be called after running @see execute()
*
* @return array
*/
public function getRids() {
if($this->result_rids === null) throw new StructException('rids are only accessible after executing the search');
return $this->result_rids;
}
/**
* Execute this search and return the result
*
@ -314,6 +329,7 @@ class Search {
}
$this->result_pids[] = $row['PID'];
$this->result_rids[] = $row['rid'];
$result[] = $resrow;
}
@ -342,7 +358,8 @@ class Search {
} else {
// first table
if(!$schema->isLookup()) {
// FIXME this breaks page search, a different check is needed
if(false) {
$QB->addTable('schema_assignments');
$QB->filters()->whereAnd("$datatable.pid = schema_assignments.pid");
$QB->filters()->whereAnd("schema_assignments.tbl = '{$schema->getTable()}'");
@ -352,6 +369,7 @@ class Search {
}
$QB->addTable($datatable);
$QB->addSelectColumn($datatable, 'rid');
$QB->addSelectColumn($datatable, 'pid', 'PID');
$QB->addGroupByColumn($datatable, 'pid');
@ -513,8 +531,9 @@ class Search {
if(!$this->schemas) throw new StructException('noschemas');
$schema_list = array_keys($this->schemas);
// FIXME check for page schema?
// add "fake" column for special col
if(!(reset($this->schemas)->isLookup())) {
// if(!(reset($this->schemas)->isLookup())) {
if($colname == '%pageid%') {
return new PageColumn(0, new Page(), $schema_list[0]);
}
@ -530,11 +549,11 @@ class Search {
if ($colname == '%lastsummary%') {
return new SummaryColumn(0, new AutoSummary(), $schema_list[0]);
}
} else {
// } else {
if($colname == '%rowid%') {
return new RowColumn(0, new Decimal(), $schema_list[0]);
}
}
// }
list($colname, $table) = $this->resolveColumn($colname);

View File

@ -21,17 +21,17 @@ var LookupEditor = function (idx, table) {
return;
}
var pid = $me.data('pid');
var rid = $me.data('rid');
// empty header cells
if (!pid) {
if (!rid) {
$me.append('<th class="action"></th>');
return;
}
// delete buttons for rows
var $td = jQuery('<td class="action"></td>');
if (pid === '') return;
if (rid === '') return;
var $btn = jQuery('<button><i class="ui-icon ui-icon-trash"></i></button>')
.addClass('delete')
@ -45,7 +45,7 @@ var LookupEditor = function (idx, table) {
{
call: 'plugin_struct_lookup_delete',
schema: schema,
pid: pid,
rid: rid,
sectok: $me.parents('.structlookup').find('.struct_entry_form input[name=sectok]').val()
}
)

View File

@ -39,10 +39,25 @@ class syntax_plugin_struct_lookup extends syntax_plugin_struct_table {
$config = parent::handle($match, $state, $pos, $handler);
if(is_null($config)) return null;
$config = $this->addTypeFilter($config);
// adjust some things for the lookup editor
$config['cols'] = array('*'); // always select all columns
if(isset($config['rownumbers'])) unset($config['rownumbers']); // this annoying to update dynamically
return $config;
}
/**
* Filter based on primary key columns
*
* @param array $config
* @return array
*/
protected function addTypeFilter($config)
{
$config['filter'][] = ['%rowid%', '!=', (string)\dokuwiki\plugin\struct\meta\AccessTableData::DEFAULT_PAGE_RID, 'AND'];
$config['filter'][] = ['%pageid%', '=*', '^(?![\s\S])', 'AND'];
return $config;
}
}

View File

@ -68,6 +68,9 @@ class syntax_plugin_struct_table extends DokuWiki_Syntax_Plugin {
try {
$parser = new ConfigParser($lines);
$config = $parser->getConfig();
$config = $this->addTypeFilter($config);
return $config;
} catch(StructException $e) {
msg($e->getMessage(), -1, $e->getLine(), $e->getFile());
@ -113,4 +116,16 @@ class syntax_plugin_struct_table extends DokuWiki_Syntax_Plugin {
return true;
}
/**
* Filter based on primary key columns
*
* @param array $config
* @return array
*/
protected function addTypeFilter($config)
{
$config['filter'][] = ['%rowid%', '=', (string)\dokuwiki\plugin\struct\meta\AccessTableData::DEFAULT_PAGE_RID, 'AND'];
return $config;
}
}

View File

@ -101,7 +101,8 @@ class Tag extends AbstractMultiBaseType {
}
$schema = new Schema($context->getTable());
if (!$schema->isLookup()) {
// FIXME do not break lookup autocompletion, whatever that is
if (true) {
$sql .= "AND PAGEEXISTS(D.pid) = 1\n";
$sql .= "AND GETACCESSLEVEL(D.pid) > 0\n";
}