diff --git a/src/calc2/views/help.tsx b/src/calc2/views/help.tsx index 1f38454b..e991d3c1 100644 --- a/src/calc2/views/help.tsx +++ b/src/calc2/views/help.tsx @@ -183,6 +183,38 @@ export class Help extends React.Component {
  • Thus, S ∪ SS in general.
  • +

    dum and dee

    + +

    + Tutorial D proposes two special relations, which have been given the pet names + TableDum and TableDee (abbreviated to just Dum and Dee, respectively). TableDum + denotes a relation of degree zero (no attributes) and cardinality zero (no tuples), + whereas TableDee represents a relation of degree zero and cardinality one (there is + one single tuple!).

    + +

    A predicate represented by a relation of degree zero is niladic (has no + parameters). In other words, it must be a proposition, p. If TableDee + represents p, then p is true (identity relation under join operators); + otherwise TableDum represents p and p is false. People often ask, + "What purpose can relations of degree zero possibly serve? They seem to be + of little or no value." The answer is that they represent answers to queries + of the form "Is it true that ...?" or "Are there any ...? where the + answer is just yes or no.

    + +

    Dum and Dee relations can be represented as follows:

    + + + Dum = {`{}`} -- inline relation with empty heading and no tuples
    + Dee = {`{()}`} -- inline relation with empty heading but one tuple of degree zero
    +
    + +

    Given a relation R with n (n {'> 0'}) attributes and t (t {'> 0'}) tuples

    + + + R x Dum -- returns a relation with the same schema of R but no tuples
    + R x Dee -- returns the very same relation R
    +
    +

    Alternative plain text notation

    Before we introduce how to use the operators this should be a quick introduction of a very handy feature diff --git a/src/db/parser/grammar_bags.pegjs b/src/db/parser/grammar_bags.pegjs index b971822b..24943e3c 100644 --- a/src/db/parser/grammar_bags.pegjs +++ b/src/db/parser/grammar_bags.pegjs @@ -1241,9 +1241,36 @@ tableRow return t; } +tableDum += '{' _ '}' // relation of degree zero and cardinality zero + { + return { + type: 'table', + name: '_inlineRelation'+(inlineTableNum++), + columns: [], + rows: [], + + codeInfo: getCodeInfo() + }; + } + +tableDee += '{' _ '(' _ ')' _ '}' // relation of degree zero and cardinality one + { + return { + type: 'table', + name: '_inlineRelation'+(inlineTableNum++), + columns: [], + rows: [[]], + + codeInfo: getCodeInfo() + }; + } table -= '{' _ cols:tableHeader _sl trows:(endOfLine _ tableRow _sl)* _ '}' += tableDum +/ tableDee +/ '{' _ cols:tableHeader _sl trows:(endOfLine _ tableRow _sl)* _ '}' { var numCols = cols.length; diff --git a/src/db/parser/grammar_ra.pegjs b/src/db/parser/grammar_ra.pegjs index dfc30661..8978ac19 100644 --- a/src/db/parser/grammar_ra.pegjs +++ b/src/db/parser/grammar_ra.pegjs @@ -1224,9 +1224,36 @@ tableRow return t; } +tableDum += '{' _ '}' // relation of degree zero and cardinality zero + { + return { + type: 'table', + name: '_inlineRelation'+(inlineTableNum++), + columns: [], + rows: [], + + codeInfo: getCodeInfo() + }; + } + +tableDee += '{' _ '(' _ ')' _ '}' // relation of degree zero and cardinality one + { + return { + type: 'table', + name: '_inlineRelation'+(inlineTableNum++), + columns: [], + rows: [[]], + + codeInfo: getCodeInfo() + }; + } table -= '{' _ cols:tableHeader _sl trows:(endOfLine _ tableRow _sl)* _ '}' += tableDum +/ tableDee +/ '{' _ cols:tableHeader _sl trows:(endOfLine _ tableRow _sl)* _ '}' { var numCols = cols.length; diff --git a/src/db/tests/translate_tests_bags.ts b/src/db/tests/translate_tests_bags.ts index 01b82601..cc81a704 100644 --- a/src/db/tests/translate_tests_bags.ts +++ b/src/db/tests/translate_tests_bags.ts @@ -104,6 +104,90 @@ QUnit.test('test bag R', function (assert) { assert.deepEqual(root.getResult(false), relations.R.getResult(false)); }); +QUnit.test('test dum bag 1', function (assert) { + const relations = getTestBags(); + const root = exec_ra(`pi 1->a {}`, relations); + + const ref = exec_ra(`sigma a<1 { + a + + 10 + }`, relations); + + assert.deepEqual(root.getResult(false), ref.getResult(false)); +}); + +QUnit.test('test dum bag 2', function (assert) { + const relations = getTestBags(); + const root = exec_ra(`gamma count(*)->n {}`, relations); + + const ref = exec_ra(`{ + n + + 0 + }`, relations); + + assert.deepEqual(root.getResult(false), ref.getResult(false)); +}); + +QUnit.test('test dum bag 3', function (assert) { + const relations = getTestBags(); + const root = exec_ra(`R x {}`, relations); + + const ref = exec_ra(`R - R`, relations); + + assert.deepEqual(root.getResult(false), ref.getResult(false)); +}); + +QUnit.test('test dum bag 4', function (assert) { + const relations = getTestBags(); + const root = exec_ra(`{} x R`, relations); + + const ref = exec_ra(`R - R`, relations); + + assert.deepEqual(root.getResult(false), ref.getResult(false)); +}); + +QUnit.test('test dee bag 1', function (assert) { + const relations = getTestBags(); + const root = exec_ra(`pi 1->a {()}`, relations); + + const ref = exec_ra(`{ + a + + 1 + }`, relations); + + assert.deepEqual(root.getResult(false), ref.getResult(false)); +}); + +QUnit.test('test dee bag 2', function (assert) { + const relations = getTestBags(); + const root = exec_ra(`gamma count(*)->n {()}`, relations); + + const ref = exec_ra(`{ + n + + 1 + }`, relations); + + assert.deepEqual(root.getResult(false), ref.getResult(false)); +}); + +QUnit.test('test dee bag 3', function (assert) { + const relations = getTestBags(); + const root = exec_ra(`R x {()}`, relations); + + assert.deepEqual(root.getResult(false), relations.R.getResult(false)); +}); + +QUnit.test('test dee bag 4', function (assert) { + const relations = getTestBags(); + const root = exec_ra(`{()} x R`, relations); + + assert.deepEqual(root.getResult(false), relations.R.getResult(false)); +}); + QUnit.test('test inline-bag R', function (assert) { const relations = getTestBags(); const root = exec_ra(`{ diff --git a/src/db/tests/translate_tests_ra.ts b/src/db/tests/translate_tests_ra.ts index 1202114c..39f708a0 100644 --- a/src/db/tests/translate_tests_ra.ts +++ b/src/db/tests/translate_tests_ra.ts @@ -67,6 +67,90 @@ QUnit.test('test relation', function (assert) { assert.deepEqual(root.getResult(), relations.R.getResult()); }); +QUnit.test('test dum relation 1', function (assert) { + const relations = getTestRelations(); + const root = exec_ra(`pi 1->a {}`, relations); + + const ref = exec_ra(`sigma a<1 { + a + + 10 + }`, relations); + + assert.deepEqual(root.getResult(), ref.getResult()); +}); + +QUnit.test('test dum relation 2', function (assert) { + const relations = getTestRelations(); + const root = exec_ra(`gamma count(*)->n {}`, relations); + + const ref = exec_ra(`{ + n + + 0 + }`, relations); + + assert.deepEqual(root.getResult(), ref.getResult()); +}); + +QUnit.test('test dum relation 3', function (assert) { + const relations = getTestRelations(); + const root = exec_ra(`R x {}`, relations); + + const ref = exec_ra(`R - R`, relations); + + assert.deepEqual(root.getResult(), ref.getResult()); +}); + +QUnit.test('test dum relation 4', function (assert) { + const relations = getTestRelations(); + const root = exec_ra(`{} x R`, relations); + + const ref = exec_ra(`R - R`, relations); + + assert.deepEqual(root.getResult(), ref.getResult()); +}); + +QUnit.test('test dee relation 1', function (assert) { + const relations = getTestRelations(); + const root = exec_ra(`pi 1->a {()}`, relations); + + const ref = exec_ra(`{ + a + + 1 + }`, relations); + + assert.deepEqual(root.getResult(), ref.getResult()); +}); + +QUnit.test('test dee relation 2', function (assert) { + const relations = getTestRelations(); + const root = exec_ra(`gamma count(*)->n {()}`, relations); + + const ref = exec_ra(`{ + n + + 1 + }`, relations); + + assert.deepEqual(root.getResult(), ref.getResult()); +}); + +QUnit.test('test dee relation 3', function (assert) { + const relations = getTestRelations(); + const root = exec_ra(`R x {()}`, relations); + + assert.deepEqual(root.getResult(), relations.R.getResult()); +}); + +QUnit.test('test dee relation 4', function (assert) { + const relations = getTestRelations(); + const root = exec_ra(`{()} x R`, relations); + + assert.deepEqual(root.getResult(), relations.R.getResult()); +}); + QUnit.test('test inline-relation', function (assert) { const relations = getTestRelations(); const root = exec_ra(`{