How to be Pythonic? Design a Query Language in Python

Β 

Cheuk Ting Ho

Pythonic means code that doesn't just get the syntax right but that follows the conventions of the Python community and uses the language in the way it is intended to be used.

- Stackoverflow

🐼

Why can't I just do it in a for-loop?

for i in (i; i < items.length ; i++)
 {
  n = items[i];
 ... now do something
 }
for i in items:
  i.perform_action()
(i.some_attribute for i in items)

🐍

Pythonic!

It all started...

Co-organizer ofΒ 

Open Source contribution

Creator of

Volenteer of

Developer Advocate of

SELECT Name from TABLE where Person_ID = (SELECT mother from TABLE where Name="John")
SELECT Name from TABLE where Person_ID = (SELECT mother from TABLE WHERE Person_ID = (SELECT mother from TABLE where Name="John"))
WOQL.and(
   WOQL.triple("v:Person", "mother", "v:MotherID"),
   WOQL.triple("v:MotherID", "name", "v:MotherName"),
   WOQL.triple("v:MotherID", "mother", "v:GrandmotherID"),
   WOQL.triple("v:GrandmotherID", "name", "v:GrandmotherName"),
)

a Query Language Client for Pythonistas and Data Scientists

WOQLpy

πŸ€”

πŸ’‘

πŸ‘πŸ‘πŸ‘πŸ‘πŸ‘πŸ‘πŸ‘πŸ‘

What is WOQLpy?

It comes with the Python Client, which you can pip install:

pip install terminusdb-client

Output to DataFrames

pip install terminusdb-client[dataframe]
WOQLDataFrame.result_to_df(result)

Change the result returned form your query into pandas DataFrame

🐼

It let's you to "talk" to TerminusDB like this:

import terminusdb_client as woql
from terminusdb_client import WOQLQuery

db_id = "pybike"
client = woql.WOQLClient(server_url = "http://localhost:6363")
client.connect(key="root", account="admin", user="admin")
client.create_database(db_id, accountid="admin", label = "Bike Graph",
                       description = "Create a graph with bike data")

station_dt = WOQLQuery().doctype("Station",
                            label="Bike Station",
                            description="A station where bikes are deposited")
bicycle_dt = WOQLQuery().doctype("Bicycle", label="Bicycle")
journey_dt = (
  WOQLQuery().doctype("Journey", label="Journey").
  property("start_station", "Station", label="Start Station").
  property("end_station", "Station", label="End Station").
  property("duration", "integer", label="Journey Duration").
  property("start_time", "dateTime", label="Time Started").
  property("end_time", "dateTime", label="Time Ended").
  property("journey_bicycle", "Bicycle", label="Bicycle Used")
)
schema = station_dt + bicycle_dt + journey_dt
schema.execute(client)

Instead of this:

{
  "when": [
    {
      "true": []
    },
    {
      "and": [
        {
          "add_quad": [
            "scm:Station",
            "rdf:type",
            "owl:Class",
            "db:schema"
          ]
        },
        {
          "add_quad": [
            "scm:Station",
            "rdfs:subClassOf",
            "tcs:Document",
            "db:schema"
          ]
        },
        {
          "add_quad": [
            "scm:Station",
            "rdfs:label",
            {
              "@value": "Bike Station",
              "@language": "en"
            },
            "db:schema"
          ]
        },
        {
          "add_quad": [
            "scm:end_station",
            "rdf:type",
            "owl:ObjectProperty",
            "db:schema"
          ]
        },
        {
          "add_quad": [
            "scm:end_station",
            "rdfs:range",
            "scm:Station",
            "db:schema"
          ]
        },
        {
          "add_quad": [
            "scm:end_station",
            "rdfs:domain",
            "scm:Journey",
            "db:schema"
          ]
        },
        {
          "and": [
            {
              "add_quad": [
                "scm:start_station",
                "rdf:type",
                "owl:ObjectProperty",
                "db:schema"
              ]
            },
            {
              "add_quad": [
                "scm:start_station",
                "rdfs:range",
                "scm:Station",
                "db:schema"
              ]
            },
            {
              "add_quad": [
                "scm:start_station",
                "rdfs:domain",
                "scm:Journey",
                "db:schema"
              ]
            },
            {
              "and": [
                {
                  "add_quad": [
                    "scm:Journey",
                    "rdf:type",
                    "owl:Class",
                    "db:schema"
                  ]
                },
                {
                  "add_quad": [
                    "scm:Journey",
                    "rdfs:subClassOf",
                    "tcs:Document",
                    "db:schema"
                  ]
                },
                {
                  "add_quad": [
                    "scm:Journey",
                    "rdfs:label",
                    {
                      "@value": "Journey",
                      "@language": "en"
                    },
                    "db:schema"
                  ]
                }
              ]
            },
            {
              "add_quad": [
                "scm:start_station",
                "rdfs:label",
                {
                  "@value": "Start Station",
                  "@language": "en"
                },
                "db:schema"
              ]
            }
          ]
        },
        {
          "add_quad": [
            "scm:end_station",
            "rdfs:label",
            {
              "@value": "End Station",
              "@language": "en"
            },
            "db:schema"
          ]
        }
      ]
    }
  ]
}

You can do both

(WOQLQuery().doctype("Station")
            .label("Bike Station")
            .description("A station where bikes are deposited")
)

or

WOQLQuery().doctype("Station",
                     label="Bike Station",
                     escription="A station where bikes are deposited")

Design challanges

JavaScript: WOQL.and()

Python: WOQLQuery().and() ?

"and" is a key word, you dummy!

OK, woql_and then....πŸ˜“
WOQLQuery().woql_and()


* actually you can use the + operator thanks for the overload ability in Python

also happened to: or, not, as, from...

Integration with Jupyter notebook

Schema builder

class Coordinate(Object):
    x : float
    y : float

class Country(Document):
    name : str
    perimeter : List[Coordinate]

class Address(Object):
    street : str
    country : Country

class Person(Document):
    name : str
    age : int
    friend_of : Set['Person']

class Employee(Person):
    address_of : Address
    contact_number : str
    managed_by : 'Employee'

Look into the future

Mass loading data from DataFrame (and csvs)

🐼

Schema checker

Network graph analysing algorithms

**Your suggestion here**

TerminusDB Academy:
Β https://academy.terminusdb.com/

Β 

To get the newest updateπŸ‘:

Follow us on Twitter: @TerminusDB

Website: https://terminusdb.com/

Join the community at Discord:

https://discord.gg/Gvdqw97

We want to hear from you 😊

Conf42 - How to be Pythonic? Design a Query Language in Python

By Cheuk Ting Ho

Conf42 - How to be Pythonic? Design a Query Language in Python

  • 1,043