<jupyter_start><jupyter_text>NOTE: This notebook gets rendered with all cells executed in the `docs` directory.      FunSQL internally represents the SQL syntax using clause objects. This notebook shows how they get compiled to SQL strings and is used to test different dialects. Users don't interact with this API directly.   Working with clauses SQLClause objects correspond directly to the syntax of the SQL language. A SQL query can be assembled by constructing clauses and chaining them. The final object can then be rendered to a string.<jupyter_code>from funsql.common import S
from funsql.clausedefs import *
from funsql.render import dialect_default
from funsql.compiler.serialize import SerializationContext, serialize<jupyter_output><empty_output><jupyter_text>The serialization of a query depends on the database dialect selected. This document uses `Sqlite`.<jupyter_code>def test_render(clause, only_query = False) -> None:
    if not only_query:
        print("clause: \n", clause, "\n", sep="")
        print("-" * 80)

    ctx = SerializationContext(dialect_default())
    serialize(clause, ctx)
    print(ctx.render())<jupyter_output><empty_output><jupyter_text>Constructing a query and serializing it.<jupyter_code>c = FROM(S.person) >> SELECT(S.person_id, S.date_of_birth)
test_render(c)<jupyter_output>clause: 
ID(person) >> FROM() >> SELECT(ID(person_id), ID(date_of_birth))

--------------------------------------------------------------------------------
query: 
SELECT
  "person_id", 
  "date_of_birth"
FROM "person"<jupyter_text>Symbols We need python strings to represent* identifiers (say, table/column/function names) * and also, literal values in SQL (say, values in the `user_name` column of type `TEXT`)To make it easy for clause constructors to distinguish between the two, we wrap identifiers in `Symbol` objects, which can be created using the shorthand `S`. So, * `SELECT(S("user_name"))` corresponds to: `SELECT user_name`* `SELECT("user_name")` corresponds to: `SELECT 'user_name'` The fluent syntax also works, that is<jupyter_code>S.user_name == S("user_name")
type(S.user_name)<jupyter_output><empty_output><jupyter_text>And to chain multiple symbols, use the utility method `qual` (for "qualifier"). FunSQL translates it to chained `ID` clauses.<jupyter_code>qual(S.schema_name, S.table_name, S.col_name)<jupyter_output><empty_output><jupyter_text>Literals These represent SQL literals and can be constructed using the `LIT` clause.<jupyter_code>c = LIT("SQL is funny!")
c<jupyter_output><empty_output><jupyter_text>The common python types are converted to SQL literals when used with a clause.<jupyter_code>import datetime

c = SELECT(None, True, 100, 200.2, "FunSQL", datetime.date(2022, 2, 1))
test_render(c)<jupyter_output>clause: 
SELECT(LIT(NULL),
       LIT(True),
       LIT(100),
       LIT(200.2),
       LIT("FunSQL"),
       LIT(DATE '2022-02-01'))

--------------------------------------------------------------------------------
query: 
SELECT
  NULL, 
  TRUE, 
  100, 
  200.2, 
  'FunSQL', 
  DATE '2022-02-01'<jupyter_text>Identifiers A SQL identifier is constructed using the `ID` clause.<jupyter_code>c = ID(S.person)
c
c = ID(S.person) >> ID(S.email_addr)
c
c = ID(S.person_id, over=ID(S.person))
test_render(c)<jupyter_output>clause: 
ID(person) >> ID(person_id)

--------------------------------------------------------------------------------
query: 
"person"."person_id"<jupyter_text>When used in the context of a SQL clause, `Symbol` objects are converted to `ID` clauses.<jupyter_code>FROM(S.person) >> SELECT(S.person_id, S.date_of_birth)<jupyter_output><empty_output><jupyter_text>Variables SQL placeholder parameters are represented using the `VAR` clause.<jupyter_code>c=VAR(S.year)
c<jupyter_output><empty_output><jupyter_text>Serializing a clause yields a `SQLString` object which also contains a list of the variables used. They can be bound to values when executing the query.<jupyter_code>c = (
    FROM(S.flights) >> 
    WHERE(OP("OR", OP("=", S.origin, VAR(S.city)), OP("=", S.dest, VAR(S.city)))) >> 
    SELECT(S.flight_id)
)
test_render(c, only_query=True)<jupyter_output>query: 
SELECT "flight_id"
FROM "flights"
WHERE (("origin" = $1) OR ("dest" = $1))

vars: [city]<jupyter_text>Operator A SQL operator can be used using the `OP` clause.<jupyter_code>c = OP(S.NOT, OP("=", S.zip, 42000))
test_render(c)
c = OP(S.CURRENT_TIMESTAMP)
test_render(c)<jupyter_output>clause: 
OP("CURRENT_TIMESTAMP")

--------------------------------------------------------------------------------
query: 
CURRENT_TIMESTAMP<jupyter_text>Composite operators can be constructed using the `KW` clause.<jupyter_code>c = OP("BETWEEN", S.year_of_birth, 2000, KW(S.AND, 2020))
test_render(c)<jupyter_output>clause: 
OP("BETWEEN", ID(year_of_birth), LIT(2000), LIT(2020) >> KW(AND))

--------------------------------------------------------------------------------
query: 
("year_of_birth" BETWEEN 2000 AND 2020)<jupyter_text>Case Case expressions are constructed using the `CASE` clause. The arguments to the constructor is an interleaved sequence of conditions (`WHEN`) and corresponding values (`THEN`). When the total number of args is odd, the last argument is used as the default value.<jupyter_code>c = CASE(OP(">", S.year_of_birth, 2000), "youngling")
test_render(c)
c = CASE(OP(">", S.year_of_birth, 2000), "youngling", "millenial")
test_render(c)<jupyter_output>clause: 
CASE(OP(">", ID(year_of_birth), LIT(2000)), LIT("youngling"), LIT("millenial"))

--------------------------------------------------------------------------------
query: 
(CASE WHEN ("year_of_birth" > 2000) THEN 'youngling' ELSE 'millenial' END)<jupyter_text>AS A SQL `AS` expression is constructed using the `AS` clause.<jupyter_code>c = ID(S.person) >> AS(S.p)
test_render(c)
c = FROM(alias("person", "p")) >> SELECT(qual("p", "person_id"))
test_render(c)<jupyter_output>clause: 
ID(person) >> AS(p) >> FROM() >> SELECT(ID(p) >> ID(person_id))

--------------------------------------------------------------------------------
query: 
SELECT "p"."person_id"
FROM "person" AS "p"<jupyter_text>Function SQL functions are represented using the `FUN` clause, with the first arg being the function name.<jupyter_code>c = FUN("CONCAT", S.city, ", ", S.state)
test_render(c)<jupyter_output>clause: 
FUN("CONCAT", ID(city), LIT(", "), ID(state))

--------------------------------------------------------------------------------
query: 
CONCAT("city", ', ', "state")<jupyter_text>Function with keyword arguments are constructed using the `KW` clause.<jupyter_code>c = FUN("SUBSTRING", S.zip, KW("FROM", 1), KW("FOR", 3))
test_render(c)<jupyter_output>clause: 
FUN("SUBSTRING", ID(zip), LIT(1) >> KW(FROM), LIT(3) >> KW(FOR))

--------------------------------------------------------------------------------
query: 
SUBSTRING("zip" FROM 1 FOR 3)<jupyter_text>Function without any arguments<jupyter_code>c = FUN("NOW")
test_render(c)<jupyter_output>clause: 
FUN("NOW")

--------------------------------------------------------------------------------
query: 
NOW()<jupyter_text>Aggregates Aggregates are defined using the `AGG` clause.<jupyter_code>c = AGG("COUNT", S("*"))
test_render(c)<jupyter_output>clause: 
AGG("COUNT", OP("*"))

--------------------------------------------------------------------------------
query: 
COUNT(*)<jupyter_text>With a `DISTINCT` modifier<jupyter_code>c = AGG("COUNT", S.birth_year, distinct=True)
test_render(c)<jupyter_output>clause: 
AGG("COUNT", distinct = True, ID(birth_year))

--------------------------------------------------------------------------------
query: 
COUNT(DISTINCT "birth_year")<jupyter_text>With a `FILTER` modifier<jupyter_code>c = AGG("COUNT", S("*"), filter_=OP("=", S.year_of_birth, 1970))
test_render(c)<jupyter_output>clause: 
AGG("COUNT", OP("*"), filter = OP("=", ID(year_of_birth), LIT(1970)))

--------------------------------------------------------------------------------
query: 
(COUNT(*) FILTER (WHERE ("year_of_birth" = 1970)))<jupyter_text>Partition Window functions can be constructed by chaining a `PARTITION` clause to an `AGG` clause.<jupyter_code>c = PARTITION(S.year_of_birth, order_by = [S.month_of_birth, S.day_of_birth]) >> AGG("ROW_NUMBER")
test_render(c)<jupyter_output>clause: 
AGG("ROW_NUMBER",
    over = PARTITION(ID(year_of_birth),
                     order_by = [ID(month_of_birth), ID(day_of_birth)]))

--------------------------------------------------------------------------------
query: 
(ROW_NUMBER() OVER (PARTITION BY "year_of_birth" ORDER BY "month_of_birth", "day_of_birth"))<jupyter_text>The `frame` argument is a `Frame` object to specify the aggregation window explicitly. Unlike regular SQL, you must specify the start/end of the window explicitly.<jupyter_code>c = PARTITION(
    order_by = [S.year_of_birth], 
    frame = Frame(
        FrameMode.GROUPS, 
        start=FrameEdge(FrameEdgeSide.PRECEDING, 2), 
        end=FrameEdge(FrameEdgeSide.CURRENT_ROW)
    )
)
test_render(c)
c = PARTITION(
    order_by = [S.year_of_birth], 
    frame = Frame(
        FrameMode.ROWS, 
        start=FrameEdge(FrameEdgeSide.PRECEDING, 2), 
        end=FrameEdge(FrameEdgeSide.FOLLOWING, 2), 
        exclude=FrameExclude.CURRENT_ROW
    )
)
test_render(c, only_query=True)
c = PARTITION(
    order_by = [S.year_of_birth], 
    frame = Frame(FrameMode.RANGE, start=FrameEdge(FrameEdgeSide.PRECEDING), end=FrameEdge(FrameEdgeSide.CURRENT_ROW))
)
test_render(c, only_query=True)
c = PARTITION(
    order_by = [S.year_of_birth], 
    frame = Frame(
        FrameMode.RANGE, 
        start=FrameEdge(FrameEdgeSide.PRECEDING), 
        end=FrameEdge(FrameEdgeSide.FOLLOWING), 
        exclude=FrameExclude.TIES
    )
)
test_render(c, only_query=True)<jupyter_output>query: 
ORDER BY "year_of_birth" RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE TIES<jupyter_text>Where The SQL `WHERE` expression is constructed using the `WHERE` clause.<jupyter_code>c = FROM(S.person) >> WHERE(OP("<", S.year_of_birth, 2000)) >> SELECT(S.person_id)
test_render(c)<jupyter_output>clause: 
ID(person) >> FROM() >> WHERE(OP("<", ID(year_of_birth), LIT(2000))) >>
SELECT(ID(person_id))

--------------------------------------------------------------------------------
query: 
SELECT "person_id"
FROM "person"
WHERE ("year_of_birth" < 2000)<jupyter_text>Limit A `LIMIT/OFFSET` expression is constructed using the `LIMIT` clause.<jupyter_code>c = FROM(S.person) >> LIMIT(100)
test_render(c, only_query=True)
c = FROM(S.person) >> LIMIT(100, offset=20) >> SELECT(S.person_id)
test_render(c, only_query=True)<jupyter_output>query: 
SELECT "person_id"
FROM "person"
OFFSET 20ROWS
FETCH NEXT 100 ROWS ONLY<jupyter_text>An offset can be specified without a limit value.<jupyter_code>c = FROM(S.person) >> ORDER(S.year_of_birth) >> SELECT(S.person_id) >> LIMIT(offset=100) 
test_render(c, only_query=True)<jupyter_output>query: 
SELECT "person_id"
FROM "person"
ORDER BY "year_of_birth"
OFFSET 100ROWS<jupyter_text>Join The SQL join operation can be expressed using the `JOIN` clause.<jupyter_code>c = (
    FROM(alias(S.person, S.p)) >> 
    JOIN(
        alias(S.location, S.l), 
        on=OP("=", qual(S.p, S.location_id), qual(S.l, S.location_id)), 
        left = True
    )
)
test_render(c)<jupyter_output>clause: 
ID(person) >> AS(p) >> FROM() >>
JOIN(ID(location) >> AS(l),
     OP("=", ID(p) >> ID(location_id), ID(l) >> ID(location_id)),
     left = True)

--------------------------------------------------------------------------------
query: 

FROM "person" AS "p"
LEFT JOIN "location" AS "l" ON ("p"."location_id" = "l"."location_id")<jupyter_text>Different types of Joins can be expressed using the available args to the `JOIN` clause.<jupyter_code>t1 = alias(S.person, "p")
t2 = alias(S.provider, "pr")
c = t1 >> JOIN(t2, OP("=", qual("p", "provider_id"), qual("pr", "id")), left=True, right=True)

test_render(c)<jupyter_output>clause: 
ID(person) >> AS(p) >>
JOIN(ID(provider) >> AS(pr),
     OP("=", ID(p) >> ID(provider_id), ID(pr) >> ID(id)),
     left = True,
     right = True)

--------------------------------------------------------------------------------
query: 
"person" AS "p"
FULL JOIN "provider" AS "pr" ON ("p"."provider_id" = "pr"."id")<jupyter_text>A cross join can be constructed by setting the `on` argument to True.<jupyter_code>t1 = alias(S.person, "p")
t2 = alias(S.provider, "pr")
c = t1 >> JOIN(t2, on=True)

test_render(c)<jupyter_output>clause: 
ID(person) >> AS(p) >> JOIN(ID(provider) >> AS(pr), LIT(True))

--------------------------------------------------------------------------------
query: 
"person" AS "p"
CROSS JOIN "provider" AS "pr"<jupyter_text>Writing a lateral join<jupyter_code>t1 = FROM(alias("person", "p"))
t2 = (
    FROM(alias("visit_occurence", "vo")) >> 
    WHERE(OP("=", qual("p", "person_id"), qual("vo", "person_id"))) >>
    ORDER(qual("vo", "start_date") >> SORT(ValueOrder.DESC)) >>
    LIMIT(1) >>
    SELECT(qual("vo", "visit_start_date")) >>
    AS(S("vo"))
)
c = t1 >> JOIN(t2, on=True, left=True, lateral=True) >> SELECT(qual("p", "person_id"), qual("vo", "visit_start_date"))

test_render(c, only_query=True)<jupyter_output>query: 
SELECT
  "p"."person_id", 
  "vo"."visit_start_date"
FROM "person" AS "p"
LEFT JOIN LATERAL (
  SELECT "vo"."visit_start_date"
  FROM "visit_occurence" AS "vo"
  WHERE ("p"."person_id" = "vo"."person_id")
  ORDER BY "vo"."start_date" DESC
  FETCH FIRST 1 ROW ONLY
) AS "vo" ON TRUE<jupyter_text>Group A SQL `Group By` expression is constructed with the `GROUP` clause.<jupyter_code>c = FROM(S.person) >> GROUP(S.year_of_birth) >> SELECT(S.year_of_birth, AGG("COUNT", S("*")))
test_render(c)<jupyter_output>clause: 
ID(person) >> FROM() >> GROUP(ID(year_of_birth)) >>
SELECT(ID(year_of_birth), AGG("COUNT", OP("*")))

--------------------------------------------------------------------------------
query: 
SELECT
  "year_of_birth", 
  COUNT(*)
FROM "person"
GROUP BY "year_of_birth"<jupyter_text>Having The SQL `Having` expression is constructed using the `HAVING` clause.<jupyter_code>c = FROM(S.person) >> GROUP(S.year_of_birth) >> HAVING(OP(">", AGG("COUNT", S("*")), 10)) >> SELECT(S.year_of_birth)
test_render(c)<jupyter_output>clause: 
ID(person) >> FROM() >> GROUP(ID(year_of_birth)) >>
HAVING(OP(">", AGG("COUNT", OP("*")), LIT(10))) >>
SELECT(ID(year_of_birth))

--------------------------------------------------------------------------------
query: 
SELECT "year_of_birth"
FROM "person"
GROUP BY "year_of_birth"
HAVING (COUNT(*) > 10)<jupyter_text>Order An `ORDER BY` expression is constructed using the `ORDER` clause. The order of values in a column is specified using a `SORT` object.<jupyter_code>c = FROM(S.person) >> ORDER(
    S.year_of_birth >> SORT(ValueOrder.ASC), 
    S.person_id
) >> SELECT(S.person_id)
test_render(c)<jupyter_output>clause: 
ID(person) >> FROM() >> ORDER(ID(year_of_birth) >> SORT(ASC), ID(person_id)) >>
SELECT(ID(person_id))

--------------------------------------------------------------------------------
query: 
SELECT "person_id"
FROM "person"
ORDER BY
  "year_of_birth" ASC, 
  "person_id"<jupyter_text>`ASC` and `DESC` are shorthands for the `SORT` object.<jupyter_code>c = FROM(S.person) >> ORDER(
    S.year_of_birth >> SORT(ValueOrder.DESC, nulls=NullsOrder.FIRST), 
    S.city >> SORT(ValueOrder.ASC),
    S.person_id
) >> SELECT(S.person_id)
test_render(c, only_query=True)<jupyter_output>query: 
SELECT "person_id"
FROM "person"
ORDER BY
  "year_of_birth" DESC NULLS FIRST, 
  "city" ASC, 
  "person_id"<jupyter_text>Union `UNION` expressions are constructed using the `UNION` clause.<jupyter_code>t1 = FROM(S.measurement) >> SELECT(S.person_id, alias("measurement_date", "date"))
t2 = FROM(S.observation) >> SELECT(S.person_id, alias("observation_date", "date"))
c = t1 >> UNION(t2)

test_render(c, only_query=True)<jupyter_output>query: 
SELECT
  "person_id", 
  "measurement_date" AS "date"
FROM "measurement"
UNION
SELECT
  "person_id", 
  "observation_date" AS "date"
FROM "observation"<jupyter_text>Using the `all_` keyword arg to construct a `UNION ALL` expression.<jupyter_code>t1 = FROM(S.measurement) >> SELECT(S.person_id, alias("measurement_date", "date"))
t2 = FROM(S.observation) >> SELECT(S.person_id, alias("observation_date", "date"))
c = t1 >> UNION(t2, all_=True)

test_render(c, only_query=True)<jupyter_output>query: 
SELECT
  "person_id", 
  "measurement_date" AS "date"
FROM "measurement"
UNION ALL
SELECT
  "person_id", 
  "observation_date" AS "date"
FROM "observation"<jupyter_text>Example of a nested UNION clause<jupyter_code>import datetime

t1 = FROM(S.measurement) >> SELECT(S.person_id, alias("measurement_date", "date"))
t2 = FROM(S.observation) >> SELECT(S.person_id, alias("observation_date", "date"))
c = t1 >> UNION(t2, all_=True) >> FROM() >> AS(S.union) >> WHERE(OP(">", S.date, datetime.date(2000, 1, 1))) >> SELECT(S.person_id)

test_render(c, only_query=True)<jupyter_output>query: 
SELECT "person_id"
FROM (
  SELECT
    "person_id", 
    "measurement_date" AS "date"
  FROM "measurement"
  UNION ALL
  SELECT
    "person_id", 
    "observation_date" AS "date"
  FROM "observation"
) AS "union"
WHERE ("date" > DATE '2000-01-01')<jupyter_text>Values `VALUES` expressions are constructed using the `VALUES` clause. The common python data types are cast as SQL literals.<jupyter_code>c = VALUES([("SQL", 1974), ("Julia", 2012), ("FunSQL", 2021)])
test_render(c, only_query=True)<jupyter_output>query: 
VALUES
  ('SQL', 1974),
  ('Julia', 2012),
  ('FunSQL', 2021)<jupyter_text>With only a single row of values<jupyter_code>c = VALUES([("SQL", "Julia", "FunSQL")])
test_render(c, only_query=True)<jupyter_output>query: 
VALUES ('SQL', 'Julia', 'FunSQL')<jupyter_text>Nested `Values` expression in a `FROM` clause<jupyter_code>c = (
    VALUES([("SQL", 1974), ("Julia", 2012), ("FunSQL", 2021)]) >> 
    AS(S.values, columns = [S.name, S.year]) >>
    FROM() >>
    SELECT(OP("*"))
)

test_render(c, only_query=True)<jupyter_output>query: 
SELECT *
FROM (
  VALUES
    ('SQL', 1974),
    ('Julia', 2012),
    ('FunSQL', 2021)
) AS "values" ("name", "year")<jupyter_text>Window Window expressions are constructed using the `WINDOW` clause.<jupyter_code>t1 = PARTITION(S.gender) >> AS(S.w1)
t2 = S.w1 >> PARTITION(S.year_of_birth, order_by=[S.month_of_birth, S.date_of_birth]) >> AS(S.w2)

c = FROM(S.person) >> WINDOW(t1, t2) >> SELECT(S.w1 >> AGG("ROW_NUMBER"), S.w2 >> AGG("ROW_NUMBER"))
test_render(c)<jupyter_output>clause: 
ID(person) >> FROM() >>
WINDOW(PARTITION(ID(gender)) >> AS(w1),
       ID(w1) >>
       PARTITION(ID(year_of_birth),
                 order_by = [ID(month_of_birth), ID(date_of_birth)]) >>
       AS(w2)) >>
SELECT(AGG("ROW_NUMBER", over = ID(w1)), AGG("ROW_NUMBER", over = ID(w2)))

--------------------------------------------------------------------------------
query: 
SELECT
  (ROW_NUMBER() OVER ("w1")), 
  (ROW_NUMBER() OVER ("w2"))
FROM "person"
WINDOW
  "w1" AS (PARTITION BY "gender"), 
  "w2" AS ("w1" PARTITION BY "year_of_birth" ORDER BY "month_of_birth", "date_of_birth")<jupyter_text>With `CTE` (Common Table Expression) clauses are constructed using the `WITH` clause.<jupyter_code>cte = (
    FROM(S.flights) >> 
    WHERE(OP("=", S.dest, "Mumbai")) >>
    SELECT(S.flight_id, S.airline) >>
    AS(S.flights_to_mumbai)
)

c = FROM(S.flights_from_mumbai) >> SELECT(S("*")) >> WITH(cte)
test_render(c)<jupyter_output>clause: 
ID(flights_from_mumbai) >> FROM() >> SELECT(OP("*")) >>
WITH(ID(flights) >> FROM() >> WHERE(OP("=", ID(dest), LIT("Mumbai"))) >>
     SELECT(ID(flight_id), ID(airline)) >>
     AS(flights_to_mumbai))

--------------------------------------------------------------------------------
query: 
WITH "flights_to_mumbai" AS (
  SELECT
    "flight_id", 
    "airline"
  FROM "flights"
  WHERE ("dest" = 'Mumbai')
)
SELECT *
FROM "flights_from_mumbai"<jupyter_text>The `WITH` clause can also be used to construct a recursive CTE.<jupyter_code>cte = SELECT(1) >> UNION(SELECT(OP("+", S.x, 1)) >> LIMIT(100)) >> AS(S.counter, columns=[S.x])

c = FROM(S.counter) >> SELECT(S.x) >> WITH(cte, recursive=True)
test_render(c)<jupyter_output>clause: 
ID(counter) >> FROM() >> SELECT(ID(x)) >>
WITH(recursive = True,
     SELECT(LIT(1)) >> UNION(SELECT(OP("+", ID(x), LIT(1))) >> LIMIT(100)) >>
     AS(counter, columns = [x]))

--------------------------------------------------------------------------------
query: 
WITH RECURSIVE "counter" ("x")  AS (
  SELECT 1
  UNION
  SELECT ("x" + 1)
  FETCH FIRST 100 ROWS ONLY
)
SELECT "x"
FROM "counter"
{'fraction_non_alphanumeric': 0.23890586352393423, 'fraction_numerical': 0.013191716378097872, 'mean_word_length': 3.3428812131423755, 'pattern_counts': {'":': 0, '<': 140, '<?xml version=': 0, '>': 405, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '43', 'dir': 'jupyter-structured-clean-dedup', 'id': '412213', 'license': 'MIT', 'n_tokens_mistral': 7565, 'n_tokens_neox': 7063, 'n_words': 1591, 'path': 'docs/development/using-clauses.ipynb', 'repo_name': 'ananis25/funsql-python', 'size': '20619'}