Skip to content

Commit

Permalink
Grammar type annotations and a few minor refactors (#8049)
Browse files Browse the repository at this point in the history
- **grammar type annotations**
- **squash NamedDDL into ObjectDDL**
- **Refactor usage of qlast.DDL**
- **generate graphviz enum hiearchy**
- **fix formatting of sql docs**
  • Loading branch information
aljazerzen authored Dec 5, 2024
1 parent a9c6fc9 commit 535620f
Show file tree
Hide file tree
Showing 30 changed files with 219 additions and 105 deletions.
13 changes: 9 additions & 4 deletions docs/reference/sql_adapter.rst
Original file line number Diff line number Diff line change
Expand Up @@ -287,20 +287,25 @@ construct is mapped to PostgreSQL schema:
``UUID``. They contain the ids of the link's target type.

- Multi properties are mapped to tables with two columns:

- ``source UUID``, which contains the id of the property's source object type,
- ``target``, which contains values of the property.

- Multi links are mapped to tables with columns:

- ``source UUID``, which contains the id of the property's source object type,
- ``target UUID``, which contains the ids of the link's target object type,
- one column for each link property, using the same rules as properties on
object types.
object types.

- Aliases are not mapped to PostgreSQL schema.

- Globals are mapped to connection settings, prefixed with ``global ``.
For example, a ``global default::username: str`` can be set using
``SET "global default::username" TO 'Tom'``.
- Globals are mapped to connection settings, prefixed with ``global``.
For example, a ``global default::username: str`` can be set using:

.. code-block:: sql
SET "global default::username" TO 'Tom'``.
- Access policies are applied to object type tables when setting
``apply_access_policies_sql`` is set to ``true``.
Expand Down
84 changes: 43 additions & 41 deletions edb/edgeql/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
# AST classes that name-clash with classes from the typing module.

import typing
import enum

from edb.common import enum as s_enum
from edb.common import ast, span
Expand Down Expand Up @@ -100,6 +99,11 @@ def dump_edgeql(self) -> None:
dump_edgeql(self)


class GrammarEntryPoint(Base):
"""Mixin denoting nodes that are entry points for EdgeQL grammar"""
__mixin_node__ = True


class OptionValue(Base):
"""An option value resulting from a syntax."""
__abstract_node__ = True
Expand Down Expand Up @@ -135,7 +139,7 @@ def __len__(self) -> int:
return len(self.options)


class Expr(Base):
class Expr(GrammarEntryPoint, Base):
"""Abstract parent for all query expressions."""

__abstract_node__ = True
Expand Down Expand Up @@ -167,11 +171,15 @@ class ModuleAliasDecl(Alias):
alias: typing.Optional[str]


class GroupingAtom(Base):
__abstract_node__ = True


class BaseObjectRef(Base):
__abstract_node__ = True


class ObjectRef(BaseObjectRef):
class ObjectRef(BaseObjectRef, GroupingAtom):
name: str
module: typing.Optional[str] = None
itemclass: typing.Optional[qltypes.SchemaObjectClass] = None
Expand Down Expand Up @@ -266,13 +274,13 @@ def integer(cls, i: int) -> Constant:
return Constant(kind=ConstantKind.INTEGER, value=str(i))


class ConstantKind(enum.IntEnum):
STRING = 0
BOOLEAN = 1
INTEGER = 2
FLOAT = 3
BIGINT = 4
DECIMAL = 5
class ConstantKind(s_enum.StrEnum):
STRING = 'STRING'
BOOLEAN = 'BOOLEAN'
INTEGER = 'INTEGER'
FLOAT = 'FLOAT'
BIGINT = 'BIGINT'
DECIMAL = 'DECIMAL'


class BytesConstant(BaseConstant):
Expand Down Expand Up @@ -360,7 +368,7 @@ class Splat(Base):
PathElement = typing.Union[Expr, Ptr, TypeIntersection, ObjectRef, Splat]


class Path(Expr):
class Path(Expr, GroupingAtom):
steps: typing.List[PathElement]
partial: bool = False
allow_factoring: bool = False
Expand Down Expand Up @@ -411,7 +419,7 @@ class Set(Expr):
#


class Command(Base):
class Command(GrammarEntryPoint, Base):
"""
A top-level node that is evaluated by our server and
cannot be a part of a sub expression.
Expand Down Expand Up @@ -493,7 +501,7 @@ class Shape(Expr):
allow_factoring: bool = False


class Query(Expr):
class Query(Expr, GrammarEntryPoint):
__abstract_node__ = True

aliases: typing.Optional[typing.List[Alias]] = None
Expand All @@ -518,11 +526,8 @@ class SelectQuery(Query):
implicit: bool = False


class GroupingIdentList(Base):
elements: typing.Tuple[typing.Union[GroupingAtom], ...]


GroupingAtom = typing.Union[ObjectRef, Path, GroupingIdentList]
class GroupingIdentList(GroupingAtom, Base):
elements: typing.Tuple[GroupingAtom, ...]


class GroupingElement(Base):
Expand Down Expand Up @@ -550,7 +555,13 @@ class GroupQuery(Query):
subject: Expr


class InternalGroupQuery(GroupQuery):
class InternalGroupQuery(Query):
subject_alias: typing.Optional[str] = None
using: typing.Optional[typing.List[AliasedExpr]]
by: typing.List[GroupingElement]

subject: Expr

group_alias: str
grouping_alias: typing.Optional[str]
from_desugaring: bool = False
Expand Down Expand Up @@ -648,9 +659,8 @@ class ReleaseSavepoint(Transaction):


class DDL(Base):
'''Abstract parent for all DDL statements.'''

__abstract_node__ = True
'''A mixin denoting DDL nodes.'''
__mixin_node__ = True


class Position(DDL):
Expand All @@ -665,11 +675,9 @@ class DDLOperation(DDL):
commands: typing.List[DDLOperation] = ast.field(factory=list)


class DDLCommand(DDLOperation):
class DDLCommand(DDLOperation, Command):
__abstract_node__ = True

aliases: typing.Optional[typing.List[Alias]] = None


class NonTransactionalDDLCommand(DDLCommand):
__abstract_node__ = True
Expand Down Expand Up @@ -722,13 +730,10 @@ class SetPointerOptionality(SetField):
fill_expr: typing.Optional[Expr] = None


class NamedDDL(DDLCommand):
class ObjectDDL(DDLCommand):
__abstract_node__ = True
name: ObjectRef


class ObjectDDL(NamedDDL):
__abstract_node__ = True
name: ObjectRef


class CreateObject(ObjectDDL):
Expand Down Expand Up @@ -757,7 +762,7 @@ class CreateExtendingObject(CreateObject):
bases: typing.List[TypeName]


class Rename(NamedDDL):
class Rename(ObjectDDL):
new_name: ObjectRef

@property
Expand All @@ -776,7 +781,7 @@ class MigrationCommand(DDLCommand):
__abstract_node__ = True


class CreateMigration(CreateObject, MigrationCommand):
class CreateMigration(CreateObject, MigrationCommand, GrammarEntryPoint):

body: NestedQLBlock
parent: typing.Optional[ObjectRef] = None
Expand Down Expand Up @@ -1246,9 +1251,6 @@ class DropIndex(DropObject, IndexCommand):
class IndexMatchCommand(ObjectDDL):

__abstract_node__ = True
__rust_ignore__ = True
object_class: qltypes.SchemaObjectClass = \
qltypes.SchemaObjectClass.INDEX_MATCH
valid_type: TypeName


Expand Down Expand Up @@ -1535,20 +1537,20 @@ class AdministerStmt(Command):


class SDL(Base):
'''Abstract parent for all SDL statements.'''
'''A mixin denoting SDL nodes.'''

__abstract_node__ = True
__mixin_node__ = True


class ModuleDeclaration(SDL):
# The 'name' is treated same as in CreateModule, for consistency,
# since this declaration also implies creating a module.
name: ObjectRef
declarations: typing.List[typing.Union[NamedDDL, ModuleDeclaration]]
declarations: typing.List[typing.Union[ObjectDDL, ModuleDeclaration]]


class Schema(SDL):
declarations: typing.List[typing.Union[NamedDDL, ModuleDeclaration]]
class Schema(SDL, GrammarEntryPoint, Base):
declarations: typing.List[typing.Union[ObjectDDL, ModuleDeclaration]]


#
Expand Down Expand Up @@ -1635,4 +1637,4 @@ def has_ddl_subcommand(
)

# A node that can have a WITH block
Statement = Query | Command | DDLCommand
Statement = Query | Command
5 changes: 4 additions & 1 deletion edb/edgeql/codegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,9 @@ def visit_GroupingOperation(self, node: qlast.GroupingOperation) -> None:
self.write(')')

def visit_GroupQuery(
self, node: qlast.GroupQuery, no_paren: bool = False
self,
node: qlast.GroupQuery | qlast.InternalGroupQuery,
no_paren: bool = False
) -> None:
# need to parenthesise when GROUP appears as an expression
parenthesise = self._needs_parentheses(node) and not no_paren
Expand Down Expand Up @@ -904,6 +906,7 @@ def _ddl_visit_body(
commands = self._ddl_clean_up_commands(commands)
if len(commands) == 1 and allow_short and not (
isinstance(commands[0], qlast.ObjectDDL)
and not isinstance(commands[0], qlast.Rename)
):
self.write(' ')
self.visit(commands[0])
Expand Down
11 changes: 0 additions & 11 deletions edb/edgeql/compiler/normalization.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,17 +187,6 @@ def normalize_ObjectRef(
ref.module = modaliases[ref.module]


@normalize.register
def normalize_DDL(
node: qlast.DDL,
*,
schema: s_schema.Schema,
modaliases: Mapping[Optional[str], str],
localnames: AbstractSet[str] = frozenset(),
) -> None:
raise AssertionError(f'normalize: cannot handle {node!r}')


def _normalize_with_block(
node: qlast.Query,
*,
Expand Down
2 changes: 1 addition & 1 deletion edb/edgeql/declarative.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ def __init__(

def sdl_to_ddl(
schema: s_schema.Schema,
documents: Mapping[str, List[qlast.DDL]],
documents: Mapping[str, List[qlast.DDLCommand]],
) -> Tuple[qlast.DDLCommand, ...]:

ddlgraph: DDLGraph = {}
Expand Down
1 change: 1 addition & 0 deletions edb/edgeql/desugar_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ def rewrite_atom(el: qlast.GroupingAtom) -> qlast.GroupingAtom:
)
return qlast.ObjectRef(name=alias)
else:
assert isinstance(el, qlast.GroupingIdentList)
return qlast.GroupingIdentList(
span=el.span,
elements=tuple(rewrite_atom(at) for at in el.elements),
Expand Down
2 changes: 1 addition & 1 deletion edb/edgeql/parser/grammar/commondl.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def _parse_language(node):

def _validate_declarations(
declarations: typing.Sequence[
typing.Union[qlast.ModuleDeclaration, qlast.NamedDDL]]
typing.Union[qlast.ModuleDeclaration, qlast.ObjectDDL]]
) -> None:
# Check that top-level declarations either use fully-qualified
# names or are module blocks.
Expand Down
1 change: 1 addition & 0 deletions edb/edgeql/parser/grammar/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def reduce_INSTANCE(self, _):


class ConfigOp(Nonterm):
val: qlast.ConfigOp

def reduce_SET_NodeName_ASSIGN_Expr(self, _s, name, _a, expr):
self.val = qlast.ConfigSet(
Expand Down
1 change: 1 addition & 0 deletions edb/edgeql/parser/grammar/ddl.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@


class DDLStmt(Nonterm):
val: qlast.DDLCommand

@parsing.inline(0)
def reduce_DatabaseStmt(self, *_):
Expand Down
Loading

0 comments on commit 535620f

Please sign in to comment.