{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Introduction to TutorialD via Jupyter Notebook\n", "\n", "Thanks for trying Project:M36 via this Jupyter notebook. TutorialD is a language for interacting with relational algebra databases, similar to SQL but without the historical cruft. This notebook is based on the [TutorialD Tutorial](https://github.com/agentm/project-m36/blob/master/docs/tutd_tutorial.markdown). \n", "\n", "[Project:M36](https://github.com/agentm/project-m36) is a feature-rich database management system (DBMS) which casts off the baggage of legacy DBMSes by adhering strictly to the mathematics of the relational algebra.\n", "\n", "Please refer to the [Project:M36 documentation](https://github.com/agentm/project-m36#documentation) for more detailed examples. Let's get started!\n", "\n", "First, let's import the Chris Date example relation variables. The relation variables provided in the example are:\n", "\n", "* `s` suppliers\n", "* `sp` supplier-parts\n", "* `p` parts" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/html": [ "ok" ], "text/plain": [ "ok" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ ":importexample cjdate" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you see an error in the previous cell regarding `project-m36-websocket-server` not being in your `PATH`, add the binary to your `PATH` and restart the jupyter server.\n", "\n", "Let's take a look at the relation variables." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
s#::Textsname::Textstatus::Integercity::Text
\"S3\"\"Blake\"30\"Paris\"
\"S5\"\"Adams\"30\"Athens\"
\"S4\"\"Clark\"20\"London\"
\"S1\"\"Smith\"20\"London\"
\"S2\"\"Jones\"10\"Paris\"
Finite 5 tuples
" ], "text/plain": [ "┌──────────┬────────┬───────────┬───────────────┐\n", "│city::Text│s#::Text│sname::Text│status::Integer│\n", "├──────────┼────────┼───────────┼───────────────┤\n", "│\"Paris\" │\"S2\" │\"Jones\" │10 │\n", "│\"London\" │\"S1\" │\"Smith\" │20 │\n", "│\"London\" │\"S4\" │\"Clark\" │20 │\n", "│\"Athens\" │\"S5\" │\"Adams\" │30 │\n", "│\"Paris\" │\"S3\" │\"Blake\" │30 │\n", "└──────────┴────────┴───────────┴───────────────┘" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ ":showexpr s" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
s#::Textp#::Textqty::Integer
\"S1\"\"P2\"200
\"S1\"\"P1\"300
\"S3\"\"P2\"200
\"S2\"\"P2\"400
\"S4\"\"P5\"400
\"S1\"\"P5\"100
\"S1\"\"P6\"100
\"S2\"\"P1\"300
\"S1\"\"P4\"200
\"S4\"\"P4\"300
\"S4\"\"P2\"200
\"S1\"\"P3\"400
Finite 12 tuples
" ], "text/plain": [ "┌────────┬────────────┬────────┐\n", "│p#::Text│qty::Integer│s#::Text│\n", "├────────┼────────────┼────────┤\n", "│\"P3\" │400 │\"S1\" │\n", "│\"P2\" │200 │\"S4\" │\n", "│\"P4\" │300 │\"S4\" │\n", "│\"P4\" │200 │\"S1\" │\n", "│\"P1\" │300 │\"S2\" │\n", "│\"P6\" │100 │\"S1\" │\n", "│\"P5\" │100 │\"S1\" │\n", "│\"P5\" │400 │\"S4\" │\n", "│\"P2\" │400 │\"S2\" │\n", "│\"P2\" │200 │\"S3\" │\n", "│\"P1\" │300 │\"S1\" │\n", "│\"P2\" │200 │\"S1\" │\n", "└────────┴────────────┴────────┘" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ ":showexpr sp" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/html": [ "
p#::Textpname::Textcolor::Textweight::Integercity::Text
\"P3\"\"Screw\"\"Blue\"17\"Oslo\"
\"P2\"\"Bolt\"\"Green\"17\"Paris\"
\"P4\"\"Screw\"\"Red\"14\"London\"
\"P6\"\"Cog\"\"Red\"19\"London\"
\"P1\"\"Nut\"\"Red\"12\"London\"
\"P5\"\"Cam\"\"Blue\"12\"Paris\"
Finite 6 tuples
" ], "text/plain": [ "┌──────────┬───────────┬────────┬───────────┬───────────────┐\n", "│city::Text│color::Text│p#::Text│pname::Text│weight::Integer│\n", "├──────────┼───────────┼────────┼───────────┼───────────────┤\n", "│\"Paris\" │\"Blue\" │\"P5\" │\"Cam\" │12 │\n", "│\"London\" │\"Red\" │\"P1\" │\"Nut\" │12 │\n", "│\"London\" │\"Red\" │\"P6\" │\"Cog\" │19 │\n", "│\"London\" │\"Red\" │\"P4\" │\"Screw\" │14 │\n", "│\"Paris\" │\"Green\" │\"P2\" │\"Bolt\" │17 │\n", "│\"Oslo\" │\"Blue\" │\"P3\" │\"Screw\" │17 │\n", "└──────────┴───────────┴────────┴───────────┴───────────────┘" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "\n", ":showexpr p" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Relational Operators\n", "\n", "### Restriction\n", "\n", "We can see that there is a many-to-many relationship between `s` (suppliers) and `p` (parts) via the `sp` relation variable.\n", "\n", "Let's look at the suppliers who are in London. This is called \"restriction\".\n", "\n", "Note that the relation attributes have appropriate types which restrict the values which they can contain." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
s#::Textsname::Textstatus::Integercity::Text
\"S4\"\"Clark\"20\"London\"
\"S1\"\"Smith\"20\"London\"
Finite 2 tuples
" ], "text/plain": [ "┌──────────┬────────┬───────────┬───────────────┐\n", "│city::Text│s#::Text│sname::Text│status::Integer│\n", "├──────────┼────────┼───────────┼───────────────┤\n", "│\"London\" │\"S1\" │\"Smith\" │20 │\n", "│\"London\" │\"S4\" │\"Clark\" │20 │\n", "└──────────┴────────┴───────────┴───────────────┘" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ ":showexpr s where city=\"London\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Join And Projection\n", "\n", "Let's examine which parts the London suppliers offer. In the following expression, we make use of the relational join operator (equivalent to `NATURAL JOIN` in SQL) and projection using the trailing curly brackets to only return the relation attributes which interest us." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
qty::Integerpname::Textp#::Text
100\"Cog\"\"P6\"
300\"Nut\"\"P1\"
300\"Screw\"\"P4\"
200\"Screw\"\"P4\"
Finite 4 tuples
" ], "text/plain": [ "┌────────┬───────────┬────────────┐\n", "│p#::Text│pname::Text│qty::Integer│\n", "├────────┼───────────┼────────────┤\n", "│\"P4\" │\"Screw\" │200 │\n", "│\"P4\" │\"Screw\" │300 │\n", "│\"P1\" │\"Nut\" │300 │\n", "│\"P6\" │\"Cog\" │100 │\n", "└────────┴───────────┴────────────┘" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ ":showexpr ((s where city=\"London\") join sp join p){p#,pname,qty}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Extend and Atom Functions\n", "\n", "We can also execute server-side functions on values and add them to our result relation." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
s#::Textstatus::Integerstatusplus10::Integer
\"S1\"2030
\"S4\"2030
\"S5\"3040
\"S3\"3040
\"S2\"1020
Finite 5 tuples
" ], "text/plain": [ "┌────────┬───────────────┬─────────────────────┐\n", "│s#::Text│status::Integer│statusplus10::Integer│\n", "├────────┼───────────────┼─────────────────────┤\n", "│\"S2\" │10 │20 │\n", "│\"S3\" │30 │40 │\n", "│\"S5\" │30 │40 │\n", "│\"S4\" │20 │30 │\n", "│\"S1\" │20 │30 │\n", "└────────┴───────────────┴─────────────────────┘" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ ":showexpr (s:{statusplus10:=add(@status,10)}){s#,status,statusplus10}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Group and Ungroup\n", "\n", "Unlike most databases, Project:M36 supports relation-valued attributes. This means that database values (atoms) can also be relations. Relation-valued attributes can be represented in the notebook as nested tables of values. Note that the nested relation's type is `relation {qty::Integer,pname::Text,s#::Text}`. \n", "\n", "Relation-valued attributes reduce tuple duplication by clearly associating certain values with their related multiple tuples. The `group` operator can also be used to create the SQL equivalent of `OUTER JOIN` but without the need for representing `NULL` in any form.\n", "\n", "Let's list the available counts for each supplier for each part." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
p#::Textavailability::relation {qty::Integer,pname::Text,s#::Text}
\"P6\"
qty::Integerpname::Texts#::Text
100\"Cog\"\"S1\"
Finite 1 tuples
\"P1\"
qty::Integerpname::Texts#::Text
300\"Nut\"\"S2\"
300\"Nut\"\"S1\"
Finite 2 tuples
\"P2\"
qty::Integerpname::Texts#::Text
200\"Bolt\"\"S4\"
200\"Bolt\"\"S1\"
400\"Bolt\"\"S2\"
200\"Bolt\"\"S3\"
Finite 4 tuples
\"P4\"
qty::Integerpname::Texts#::Text
200\"Screw\"\"S1\"
300\"Screw\"\"S4\"
Finite 2 tuples
\"P3\"
qty::Integerpname::Texts#::Text
400\"Screw\"\"S1\"
Finite 1 tuples
\"P5\"
qty::Integerpname::Texts#::Text
400\"Cam\"\"S4\"
100\"Cam\"\"S1\"
Finite 2 tuples
Finite 6 tuples
" ], "text/plain": [ "┌──────────────────────────────────────────────────────────┬────────┐\n", "│availability::relation {qty::Integer,pname::Text,s#::Text}│p#::Text│\n", "├──────────────────────────────────────────────────────────┼────────┤\n", "│┌───────────┬────────────┬────────┐ │\"P5\" │\n", "││pname::Text│qty::Integer│s#::Text│ │ │\n", "│├───────────┼────────────┼────────┤ │ │\n", "││\"Cam\" │100 │\"S1\" │ │ │\n", "││\"Cam\" │400 │\"S4\" │ │ │\n", "│└───────────┴────────────┴────────┘ │ │\n", "│┌───────────┬────────────┬────────┐ │\"P3\" │\n", "││pname::Text│qty::Integer│s#::Text│ │ │\n", "│├───────────┼────────────┼────────┤ │ │\n", "││\"Screw\" │400 │\"S1\" │ │ │\n", "│└───────────┴────────────┴────────┘ │ │\n", "│┌───────────┬────────────┬────────┐ │\"P4\" │\n", "││pname::Text│qty::Integer│s#::Text│ │ │\n", "│├───────────┼────────────┼────────┤ │ │\n", "││\"Screw\" │300 │\"S4\" │ │ │\n", "││\"Screw\" │200 │\"S1\" │ │ │\n", "│└───────────┴────────────┴────────┘ │ │\n", "│┌───────────┬────────────┬────────┐ │\"P2\" │\n", "││pname::Text│qty::Integer│s#::Text│ │ │\n", "│├───────────┼────────────┼────────┤ │ │\n", "││\"Bolt\" │200 │\"S3\" │ │ │\n", "││\"Bolt\" │400 │\"S2\" │ │ │\n", "││\"Bolt\" │200 │\"S1\" │ │ │\n", "││\"Bolt\" │200 │\"S4\" │ │ │\n", "│└───────────┴────────────┴────────┘ │ │\n", "│┌───────────┬────────────┬────────┐ │\"P1\" │\n", "││pname::Text│qty::Integer│s#::Text│ │ │\n", "│├───────────┼────────────┼────────┤ │ │\n", "││\"Nut\" │300 │\"S1\" │ │ │\n", "││\"Nut\" │300 │\"S2\" │ │ │\n", "│└───────────┴────────────┴────────┘ │ │\n", "│┌───────────┬────────────┬────────┐ │\"P6\" │\n", "││pname::Text│qty::Integer│s#::Text│ │ │\n", "│├───────────┼────────────┼────────┤ │ │\n", "││\"Cog\" │100 │\"S1\" │ │ │\n", "│└───────────┴────────────┴────────┘ │ │\n", "└──────────────────────────────────────────────────────────┴────────┘" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ ":showexpr (p join sp){qty,pname,s#,p#} group ({s#,pname,qty} as availability)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can flatten the relation-valued attributes, thereby generating more top-level tuples." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
qty::Integerpname::Texts#::Textp#::Text
400\"Screw\"\"S1\"\"P3\"
200\"Bolt\"\"S4\"\"P2\"
100\"Cog\"\"S1\"\"P6\"
100\"Cam\"\"S1\"\"P5\"
300\"Nut\"\"S2\"\"P1\"
400\"Cam\"\"S4\"\"P5\"
300\"Screw\"\"S4\"\"P4\"
200\"Bolt\"\"S1\"\"P2\"
200\"Screw\"\"S1\"\"P4\"
200\"Bolt\"\"S3\"\"P2\"
300\"Nut\"\"S1\"\"P1\"
400\"Bolt\"\"S2\"\"P2\"
Finite 12 tuples
" ], "text/plain": [ "┌────────┬───────────┬────────────┬────────┐\n", "│p#::Text│pname::Text│qty::Integer│s#::Text│\n", "├────────┼───────────┼────────────┼────────┤\n", "│\"P2\" │\"Bolt\" │400 │\"S2\" │\n", "│\"P1\" │\"Nut\" │300 │\"S1\" │\n", "│\"P2\" │\"Bolt\" │200 │\"S3\" │\n", "│\"P4\" │\"Screw\" │200 │\"S1\" │\n", "│\"P2\" │\"Bolt\" │200 │\"S1\" │\n", "│\"P4\" │\"Screw\" │300 │\"S4\" │\n", "│\"P5\" │\"Cam\" │400 │\"S4\" │\n", "│\"P1\" │\"Nut\" │300 │\"S2\" │\n", "│\"P5\" │\"Cam\" │100 │\"S1\" │\n", "│\"P6\" │\"Cog\" │100 │\"S1\" │\n", "│\"P2\" │\"Bolt\" │200 │\"S4\" │\n", "│\"P3\" │\"Screw\" │400 │\"S1\" │\n", "└────────┴───────────┴────────────┴────────┘" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ ":showexpr ((p join sp){qty,pname,s#,p#} group ({s#,pname,qty} as availability)) ungroup availability" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Database State Operators\n", "\n", "Thus far, we have only been inspecting the database state. Next, let's cover some database update operators. These operators are all similar to SQL operators, so we don't need a lot of exposition." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Insert" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/html": [ "ok" ], "text/plain": [ "ok" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "insert s relation{tuple{s# \"S6\", sname \"Bob\", status 50, city \"Boston\"}}" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
city::Texts#::Textsname::Textstatus::Integer
\"Boston\"\"S6\"\"Bob\"50
\"Paris\"\"S3\"\"Blake\"30
\"Athens\"\"S5\"\"Adams\"30
\"London\"\"S4\"\"Clark\"20
\"London\"\"S1\"\"Smith\"20
\"Paris\"\"S2\"\"Jones\"10
Finite 6 tuples
" ], "text/plain": [ "┌──────────┬────────┬───────────┬───────────────┐\n", "│city::Text│s#::Text│sname::Text│status::Integer│\n", "├──────────┼────────┼───────────┼───────────────┤\n", "│\"Paris\" │\"S2\" │\"Jones\" │10 │\n", "│\"London\" │\"S1\" │\"Smith\" │20 │\n", "│\"London\" │\"S4\" │\"Clark\" │20 │\n", "│\"Athens\" │\"S5\" │\"Adams\" │30 │\n", "│\"Paris\" │\"S3\" │\"Blake\" │30 │\n", "│\"Boston\" │\"S6\" │\"Bob\" │50 │\n", "└──────────┴────────┴───────────┴───────────────┘" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ ":showexpr s" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Delete" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/html": [ "ok" ], "text/plain": [ "ok" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "delete s where sname=\"Bob\"" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
city::Texts#::Textsname::Textstatus::Integer
\"Paris\"\"S3\"\"Blake\"30
\"Athens\"\"S5\"\"Adams\"30
\"London\"\"S4\"\"Clark\"20
\"London\"\"S1\"\"Smith\"20
\"Paris\"\"S2\"\"Jones\"10
Finite 5 tuples
" ], "text/plain": [ "┌──────────┬────────┬───────────┬───────────────┐\n", "│city::Text│s#::Text│sname::Text│status::Integer│\n", "├──────────┼────────┼───────────┼───────────────┤\n", "│\"Paris\" │\"S2\" │\"Jones\" │10 │\n", "│\"London\" │\"S1\" │\"Smith\" │20 │\n", "│\"London\" │\"S4\" │\"Clark\" │20 │\n", "│\"Athens\" │\"S5\" │\"Adams\" │30 │\n", "│\"Paris\" │\"S3\" │\"Blake\" │30 │\n", "└──────────┴────────┴───────────┴───────────────┘" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ ":showexpr s" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Update" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/html": [ "ok" ], "text/plain": [ "ok" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "update s where city=\"London\" (status:=90)" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
city::Texts#::Textsname::Textstatus::Integer
\"London\"\"S1\"\"Smith\"90
\"Paris\"\"S3\"\"Blake\"30
\"Athens\"\"S5\"\"Adams\"30
\"London\"\"S4\"\"Clark\"90
\"Paris\"\"S2\"\"Jones\"10
Finite 5 tuples
" ], "text/plain": [ "┌──────────┬────────┬───────────┬───────────────┐\n", "│city::Text│s#::Text│sname::Text│status::Integer│\n", "├──────────┼────────┼───────────┼───────────────┤\n", "│\"Paris\" │\"S2\" │\"Jones\" │10 │\n", "│\"London\" │\"S4\" │\"Clark\" │90 │\n", "│\"Athens\" │\"S5\" │\"Adams\" │30 │\n", "│\"Paris\" │\"S3\" │\"Blake\" │30 │\n", "│\"London\" │\"S1\" │\"Smith\" │90 │\n", "└──────────┴────────┴───────────┴───────────────┘" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ ":showexpr s" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Assign" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/html": [ "ok" ], "text/plain": [ "ok" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "london_suppliers := s where city=\"London\"" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
city::Texts#::Textsname::Textstatus::Integer
\"London\"\"S1\"\"Smith\"90
\"London\"\"S4\"\"Clark\"90
Finite 2 tuples
" ], "text/plain": [ "┌──────────┬────────┬───────────┬───────────────┐\n", "│city::Text│s#::Text│sname::Text│status::Integer│\n", "├──────────┼────────┼───────────┼───────────────┤\n", "│\"London\" │\"S4\" │\"Clark\" │90 │\n", "│\"London\" │\"S1\" │\"Smith\" │90 │\n", "└──────────┴────────┴───────────┴───────────────┘" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ ":showexpr london_suppliers" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Constraints\n", "\n", "Project:M36 supports too many features to cover in one notebook, but constraints are certainly essential.\n", "\n", "Let's examine the current constraints." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
name::Textsub::Textsuper::Text
\"p_pkey\"\"NotEquals (Project (AttributeNames (fromList [\\\"b\\\"])) (Extend (AttributeExtendTupleExpr \\\"b\\\" (FunctionAtomExpr \\\"count\\\" [AttributeAtomExpr \\\"a\\\"] ())) (Extend (AttributeExtendTupleExpr \\\"a\\\" (RelationAtomExpr (RelationVariable \\\"p\\\" ()))) (ExistingRelation (Relation [] (RelationTupleSet {asList = [RelationTuple [] []]})))))) (Project (AttributeNames (fromList [\\\"b\\\"])) (Extend (AttributeExtendTupleExpr \\\"b\\\" (FunctionAtomExpr \\\"count\\\" [AttributeAtomExpr \\\"a\\\"] ())) (Extend (AttributeExtendTupleExpr \\\"a\\\" (RelationAtomExpr (Project (AttributeNames (fromList [\\\"p#\\\"])) (RelationVariable \\\"p\\\" ())))) (ExistingRelation (Relation [] (RelationTupleSet {asList = [RelationTuple [] []]}))))))\"\"ExistingRelation (Relation [] (RelationTupleSet {asList = []}))\"
\"s_pkey\"\"NotEquals (Project (AttributeNames (fromList [\\\"b\\\"])) (Extend (AttributeExtendTupleExpr \\\"b\\\" (FunctionAtomExpr \\\"count\\\" [AttributeAtomExpr \\\"a\\\"] ())) (Extend (AttributeExtendTupleExpr \\\"a\\\" (RelationAtomExpr (RelationVariable \\\"s\\\" ()))) (ExistingRelation (Relation [] (RelationTupleSet {asList = [RelationTuple [] []]})))))) (Project (AttributeNames (fromList [\\\"b\\\"])) (Extend (AttributeExtendTupleExpr \\\"b\\\" (FunctionAtomExpr \\\"count\\\" [AttributeAtomExpr \\\"a\\\"] ())) (Extend (AttributeExtendTupleExpr \\\"a\\\" (RelationAtomExpr (Project (AttributeNames (fromList [\\\"s#\\\"])) (RelationVariable \\\"s\\\" ())))) (ExistingRelation (Relation [] (RelationTupleSet {asList = [RelationTuple [] []]}))))))\"\"ExistingRelation (Relation [] (RelationTupleSet {asList = []}))\"
\"sp_pkey\"\"NotEquals (Project (AttributeNames (fromList [\\\"b\\\"])) (Extend (AttributeExtendTupleExpr \\\"b\\\" (FunctionAtomExpr \\\"count\\\" [AttributeAtomExpr \\\"a\\\"] ())) (Extend (AttributeExtendTupleExpr \\\"a\\\" (RelationAtomExpr (RelationVariable \\\"sp\\\" ()))) (ExistingRelation (Relation [] (RelationTupleSet {asList = [RelationTuple [] []]})))))) (Project (AttributeNames (fromList [\\\"b\\\"])) (Extend (AttributeExtendTupleExpr \\\"b\\\" (FunctionAtomExpr \\\"count\\\" [AttributeAtomExpr \\\"a\\\"] ())) (Extend (AttributeExtendTupleExpr \\\"a\\\" (RelationAtomExpr (Project (AttributeNames (fromList [\\\"p#\\\",\\\"s#\\\"])) (RelationVariable \\\"sp\\\" ())))) (ExistingRelation (Relation [] (RelationTupleSet {asList = [RelationTuple [] []]}))))))\"\"ExistingRelation (Relation [] (RelationTupleSet {asList = []}))\"
Finite 3 tuples
" ], "text/plain": [ "┌──────────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬─────────────────────────────────────────────────────────────────┐\n", "│name::Text│sub::Text │super::Text │\n", "├──────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────┤\n", "│\"sp_pkey\" │\"NotEquals (Project (AttributeNames (fromList [\\\"b\\\"])) (Extend (AttributeExtendTupleExpr \\\"b\\\" (FunctionAtomExpr \\\"count\\\" [AttributeAtomExpr \\\"a\\\"] ())) (Extend (AttributeExtendTupleExpr \\\"a\\\" (RelationAtomExpr (RelationVariable \\\"sp\\\" ()))) (ExistingRelation (Relation [] (RelationTupleSet {asList = [RelationTuple [] []]})))))) (Project (AttributeNames (fromList [\\\"b\\\"])) (Extend (AttributeExtendTupleExpr \\\"b\\\" (FunctionAtomExpr \\\"count\\\" [AttributeAtomExpr \\\"a\\\"] ())) (Extend (AttributeExtendTupleExpr \\\"a\\\" (RelationAtomExpr (Project (AttributeNames (fromList [\\\"p#\\\",\\\"s#\\\"])) (RelationVariable \\\"sp\\\" ())))) (ExistingRelation (Relation [] (RelationTupleSet {asList = [RelationTuple [] []]}))))))\"│\"ExistingRelation (Relation [] (RelationTupleSet {asList = []}))\"│\n", "│\"s_pkey\" │\"NotEquals (Project (AttributeNames (fromList [\\\"b\\\"])) (Extend (AttributeExtendTupleExpr \\\"b\\\" (FunctionAtomExpr \\\"count\\\" [AttributeAtomExpr \\\"a\\\"] ())) (Extend (AttributeExtendTupleExpr \\\"a\\\" (RelationAtomExpr (RelationVariable \\\"s\\\" ()))) (ExistingRelation (Relation [] (RelationTupleSet {asList = [RelationTuple [] []]})))))) (Project (AttributeNames (fromList [\\\"b\\\"])) (Extend (AttributeExtendTupleExpr \\\"b\\\" (FunctionAtomExpr \\\"count\\\" [AttributeAtomExpr \\\"a\\\"] ())) (Extend (AttributeExtendTupleExpr \\\"a\\\" (RelationAtomExpr (Project (AttributeNames (fromList [\\\"s#\\\"])) (RelationVariable \\\"s\\\" ())))) (ExistingRelation (Relation [] (RelationTupleSet {asList = [RelationTuple [] []]}))))))\" │\"ExistingRelation (Relation [] (RelationTupleSet {asList = []}))\"│\n", "│\"p_pkey\" │\"NotEquals (Project (AttributeNames (fromList [\\\"b\\\"])) (Extend (AttributeExtendTupleExpr \\\"b\\\" (FunctionAtomExpr \\\"count\\\" [AttributeAtomExpr \\\"a\\\"] ())) (Extend (AttributeExtendTupleExpr \\\"a\\\" (RelationAtomExpr (RelationVariable \\\"p\\\" ()))) (ExistingRelation (Relation [] (RelationTupleSet {asList = [RelationTuple [] []]})))))) (Project (AttributeNames (fromList [\\\"b\\\"])) (Extend (AttributeExtendTupleExpr \\\"b\\\" (FunctionAtomExpr \\\"count\\\" [AttributeAtomExpr \\\"a\\\"] ())) (Extend (AttributeExtendTupleExpr \\\"a\\\" (RelationAtomExpr (Project (AttributeNames (fromList [\\\"p#\\\"])) (RelationVariable \\\"p\\\" ())))) (ExistingRelation (Relation [] (RelationTupleSet {asList = [RelationTuple [] []]}))))))\" │\"ExistingRelation (Relation [] (RelationTupleSet {asList = []}))\"│\n", "└──────────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴─────────────────────────────────────────────────────────────────┘" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ ":constraints" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Constraints are represented as \"inclusion dependencies\". An inclusion dependency is a generalization of all possible constraints on the database and can represent keys, uniqueness constraints, foreign key constraints, as well as span multiple relation variables.\n", "\n", "An inclusion dependency requires that the result of relational expression `sub` is a subset of relational expression `super`.\n", "\n", "Project:M36 includes some utilities to generate inclusion dependencies." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/html": [ "ok" ], "text/plain": [ "ok" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "sandwich := relation{tuple{name \"Cheese\", price 4},tuple{name \"Tuna\", price 5}}" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/html": [ "ok" ], "text/plain": [ "ok" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "key sandwich_name{name} sandwich" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "ename": "TutorialDError", "evalue": "", "output_type": "error", "traceback": [ "InclusionDependencyCheckError \"sandwich_name\"" ] } ], "source": [ "insert sandwich relation{tuple{name \"Tuna\", price 6}}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Jupyter Kernel Features\n", "\n", "By default, the TutorialD kernel will automatically start a `project-m36-websocket-server` when the first TutorialD command is executed. For this to work, `project-m36-websocket-server` must be in the jupyter server's `PATH` environment variable.\n", "\n", "### Magic\n", "\n", "Like the python kernel, the TutorialD kernel includes some commands to interact directly with the kernel. These commands are not passed to the TutorialD interpreter.\n", "\n", "* `%help` brings up some help which includes links to additional documentation\n", "* `%connect ws://: ` connects to the `project-m36-websocket-server` already running. For example:\n", " ```\n", " %connect ws://localhost:64000 employees\n", " ```\n", " connects to the websocket server running on the localhost on port 64000 and selects the database named \"employees\". Note that the database name is not part of the websocket URL.\n", " \n", "## Conclusion\n", "\n", "[Project:M36](https://github.com/agentm/project-m36) is a fully-featured relational algebra engine suitable for use a database. It sets out to prove that sticking to the mathematical underpinnings of the relational algebra is straightforward and results in improved correctness and performance.\n", "\n", "If you would like to learn more, please refer to the [documentation](https://github.com/agentm/project-m36#documentation) and join our welcoming [community](https://github.com/agentm/project-m36#community) to ask questions." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "TutorialD (Project:M36)", "language": "TutorialD", "name": "tutd" }, "language_info": { "file_extension": ".tutd", "mimetype": "text/x-tutd", "name": "TutorialD" } }, "nbformat": 4, "nbformat_minor": 2 }