Skip to content

Commit

Permalink
feat(autocomplete): Updates and fixes to autocomplete (#20271)
Browse files Browse the repository at this point in the history
* Updates and fixes to autocomplete

* Added better support for types
  • Loading branch information
Gilbert09 authored Feb 12, 2024
1 parent de278a2 commit 84ef17b
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 7 deletions.
8 changes: 8 additions & 0 deletions frontend/src/lib/components/CodeEditor.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents {
display: block !important;
}

.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .left > .signature-label {
width: 100%;
text-align: right;
}
2 changes: 2 additions & 0 deletions frontend/src/lib/components/CodeEditors.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import './CodeEditor.scss'

import MonacoEditor, { type EditorProps } from '@monaco-editor/react'
import { useValues } from 'kea'
import { Spinner } from 'lib/lemon-ui/Spinner'
Expand Down
8 changes: 7 additions & 1 deletion frontend/src/queries/nodes/HogQLQuery/HogQLQueryEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,10 @@ export function HogQLQueryEditor(props: HogQLQueryEditorProps): JSX.Element {
const sortText = kindToSortText(item.kind, item.label)

return {
label: item.label,
label: {
label: item.label,
detail: item.detail,
},
documentation: item.documentation,
insertText: item.insertText,
range: {
Expand Down Expand Up @@ -338,6 +341,9 @@ export function HogQLQueryEditor(props: HogQLQueryEditorProps): JSX.Element {
scrollBeyondLastLine: false,
automaticLayout: true,
fixedOverflowWidgets: true,
suggest: {
showInlineDetails: true,
},
}}
/>
</div>
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/queries/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,10 @@
"AutocompleteCompletionItem": {
"additionalProperties": false,
"properties": {
"detail": {
"description": "A human-readable string with additional information about this item, like type or symbol information.",
"type": "string"
},
"documentation": {
"description": "A human-readable string that represents a doc-comment.",
"type": "string"
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/queries/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,11 @@ export interface AutocompleteCompletionItem {
* A human-readable string that represents a doc-comment.
*/
documentation?: string
/**
* A human-readable string with additional information
* about this item, like type or symbol information.
*/
detail?: string
/**
* A string or snippet that should be inserted in a document when selecting
* this completion.
Expand Down
48 changes: 42 additions & 6 deletions posthog/hogql/autocomplete.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,27 @@ def constant_type_to_database_field(constant_type: ConstantType, name: str) -> D
return DatabaseField(name=name)


def convert_field_or_table_to_type_string(field_or_table: FieldOrTable) -> str:
if isinstance(field_or_table, ast.BooleanDatabaseField):
return "Boolean"
if isinstance(field_or_table, ast.IntegerDatabaseField):
return "Integer"
if isinstance(field_or_table, ast.FloatDatabaseField):
return "Float"
if isinstance(field_or_table, ast.StringDatabaseField):
return "String"
if isinstance(field_or_table, ast.DateTimeDatabaseField):
return "DateTime"
if isinstance(field_or_table, ast.DateDatabaseField):
return "Date"
if isinstance(field_or_table, ast.StringJSONDatabaseField):
return "Object"
if isinstance(field_or_table, (ast.Table, ast.LazyJoin)):
return "Table"

return ""


def get_table(context: HogQLContext, join_expr: ast.JoinExpr, ctes: Optional[Dict[str, CTE]]) -> None | Table:
assert context.database is not None

Expand Down Expand Up @@ -165,15 +186,17 @@ def extend_responses(
suggestions: List[AutocompleteCompletionItem],
kind: Kind = Kind.Variable,
insert_text: Optional[Callable[[str], str]] = None,
details: Optional[List[str | None]] = None,
) -> None:
suggestions.extend(
[
AutocompleteCompletionItem(
insertText=insert_text(key) if insert_text is not None else key,
label=key,
kind=kind,
detail=details[index] if details is not None else None,
)
for key in keys
for index, key in enumerate(keys)
]
)

Expand Down Expand Up @@ -208,7 +231,10 @@ def get_hogql_autocomplete(query: HogQLAutocomplete, team: Team) -> HogQLAutocom

select_ast = parse_select(query.select)
if query.filters:
select_ast = cast(ast.SelectQuery, replace_filters(select_ast, query.filters, team))
try:
select_ast = cast(ast.SelectQuery, replace_filters(select_ast, query.filters, team))
except Exception:
pass

if isinstance(select_ast, ast.SelectQuery):
ctes = select_ast.ctes
Expand Down Expand Up @@ -256,8 +282,14 @@ def get_hogql_autocomplete(query: HogQLAutocomplete, team: Team) -> HogQLAutocom

if is_last_part:
if last_table.fields.get(str(chain_part)) is None:
fields = list(table.fields.keys())
extend_responses(fields, response.suggestions)
keys: List[str] = []
details: List[str | None] = []
table_fields = list(table.fields.items())
for field_name, field_or_table in table_fields:
keys.append(field_name)
details.append(convert_field_or_table_to_type_string(field_or_table))

extend_responses(keys=keys, suggestions=response.suggestions, details=details)

available_functions = ALL_EXPOSED_FUNCTION_NAMES
extend_responses(
Expand Down Expand Up @@ -289,9 +321,13 @@ def get_hogql_autocomplete(query: HogQLAutocomplete, team: Team) -> HogQLAutocom
name__contains=match_term,
team_id=team.pk,
type=property_type,
)[:PROPERTY_DEFINITION_LIMIT].values("name")
)[:PROPERTY_DEFINITION_LIMIT].values("name", "property_type")

extend_responses([prop["name"] for prop in properties], response.suggestions)
extend_responses(
keys=[prop["name"] for prop in properties],
suggestions=response.suggestions,
details=[prop["property_type"] for prop in properties],
)
elif isinstance(field, VirtualTable) or isinstance(field, LazyTable):
fields = list(last_table.fields.keys())
extend_responses(fields, response.suggestions)
Expand Down
4 changes: 4 additions & 0 deletions posthog/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ class AutocompleteCompletionItem(BaseModel):
model_config = ConfigDict(
extra="forbid",
)
detail: Optional[str] = Field(
default=None,
description="A human-readable string with additional information about this item, like type or symbol information.",
)
documentation: Optional[str] = Field(
default=None, description="A human-readable string that represents a doc-comment."
)
Expand Down
1 change: 1 addition & 0 deletions posthog/warehouse/api/saved_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ def validate_query(self, query):
_is_valid_view = is_valid_view(select_ast)
if not _is_valid_view:
raise exceptions.ValidationError(detail="Ensure all fields are aliased")

try:
print_ast(
node=select_ast,
Expand Down

0 comments on commit 84ef17b

Please sign in to comment.