Tidy up the public module level statics (#6032)

Tidies up a lot of PUBLIC module statics - marked some as PRIVATE, made some methods of types.
This commit is contained in:
James Dunkerley 2023-03-22 18:02:37 +00:00 committed by GitHub
parent 1b30a5275f
commit dd009fd1af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 353 additions and 334 deletions

1
.github/CODEOWNERS vendored
View File

@ -23,6 +23,7 @@ Cargo.toml
# GUI
/app/gui/ @MichaelMauderer @wdanilo @farmaazon @mwu-tow @kazcw
/app/gui/view/ @MichaelMauderer @wdanilo @farmaazon @kazcw
/app/gui/view/graph-editor/src/builtin/visualization/java_script/ @MichaelMauderer @wdanilo @farmaazon @kazcw @jdunkerley
/app/ide-desktop/ @MichaelMauderer @wdanilo @kazcw
# Engine (old)

View File

@ -160,7 +160,7 @@ class TableVisualization extends Visualization {
rowData = parsedData.json
dataTruncated = parsedData.all_rows_count !== parsedData.json.length
} else if (parsedData.json != null && isObjectMatrix(parsedData.json)) {
let firstKeys = Object.keys(data[0])
let firstKeys = Object.keys(parsedData.json[0])
columnDefs = firstKeys.map(field => ({ field }))
rowData = parsedData.json.map(obj =>
firstKeys.reduce((acc, key) => ({ ...acc, [key]: toRender(obj[key]) }), {})

View File

@ -268,23 +268,37 @@ make_field_name_selector : JS_Object -> Display -> Single_Choice
make_field_name_selector js_object display=Display.Always =
Single_Choice display=display values=(js_object.field_names.map n->(Option n n.pretty))
## PRIVATE
Make a new JavaScript object.
foreign js new_object = """
return {}
## PRIVATE
Parse a text value into JavaScript object.
foreign js json_parse text = """
return JSON.parse(text)
## PRIVATE
Convert a JavaScript object to a text value.
foreign js json_stringify js_object = """
return JSON.stringify(js_object)
## PRIVATE
Check a JavaScript object has a given property.
foreign js has_property js_object key = """
return js_object.hasOwnProperty(key)
## PRIVATE
Get a value from a JavaScript object.
foreign js get_value object key = """
return object[key]
## PRIVATE
Set a value on a JavaScript object and return the new object.
foreign js set_value object key value = """
return {...object, [key]: value}
## PRIVATE
Gets all the property names of a JavaScript object.
foreign js get_property_names object = """
return Object.getOwnPropertyNames(object)

View File

@ -10,7 +10,7 @@ from project.Data.Boolean import True, False
polyglot java import org.enso.base.ObjectComparator
## ADVANCED
## PRIVATE
Creates a Java Comparator object which can call back to Enso for comparison
of non-primitive types.
@ -26,7 +26,7 @@ new custom_comparator=Nothing =
Nothing -> ObjectComparator.getInstance (comparator_to_java Ordering.compare)
_ -> ObjectComparator.new (comparator_to_java custom_comparator)
## ADVANCED
## PRIVATE
Create a Java Comparator with the specified Text_Ordering
Arguments:

View File

@ -13,7 +13,7 @@ import project.Error.Error
import project.Meta
import project.Nothing.Nothing
import project.Panic.Panic
import project.Polyglot
import project.Polyglot.Polyglot
from project.Data.Boolean import Boolean, True, False

View File

@ -22,7 +22,6 @@ import project.Math
import project.Meta
import project.Nothing.Nothing
import project.Panic.Panic
import project.Polyglot
from project.Data.Boolean import Boolean, True, False
from project.Data.Time.Date_Time import ensure_in_epoch

View File

@ -14,8 +14,8 @@ import project.Math
import project.Meta
import project.Nothing.Nothing
import project.Panic.Panic
import project.Polyglot
import project.Polyglot.Java
import project.Polyglot.Polyglot
import project.Runtime
import project.System
import project.System.Environment
@ -44,8 +44,8 @@ export project.Math
export project.Meta
export project.Nothing.Nothing
export project.Panic.Panic
export project.Polyglot
export project.Polyglot.Java
export project.Polyglot.Polyglot
export project.Runtime
export project.System
export project.System.Environment

View File

@ -14,7 +14,6 @@ import project.Nothing.Nothing
import project.Polyglot.Java
import project.Error.Error as Base_Error
import project.Polyglot as Base_Polyglot
from project.Data.Boolean import Boolean, True, False

View File

@ -1,117 +1,160 @@
## A module representing interactions with polyglot languages.
Polyglot is a term that refers to other languages (such as Java) that are
running on the same JVM.
import project.Any.Any
import project.Data.Array.Array
import project.Data.Boolean.Boolean
import project.Data.Numbers.Integer
import project.Data.Text.Text
import project.Data.Vector.Vector
import project.Nothing.Nothing
import project.Runtime.Source_Location.Source_Location
@Builtin_Type
type Polyglot
## Reads the number of elements in a given polyglot array object.
## Reads the number of elements in a given polyglot array object.
Arguments:
- array: a polyglot array object, originating in any supported language.
get_array_size : Any -> Integer
get_array_size array = @Builtin_Method "Polyglot.get_array_size"
Arguments:
- array: a polyglot array object, originating in any supported language.
get_array_size : Any -> Integer
get_array_size array = @Builtin_Method "Polyglot.get_array_size"
## Reads the element in a given polyglot array object.
## Reads the element in a given polyglot array object.
Arguments:
- index: The index to get the element from.
read_array_element : Any -> Integer -> Any
read_array_element array index = @Builtin_Method "Polyglot.read_array_element"
Arguments:
- index: The index to get the element from.
read_array_element : Any -> Integer -> Any
read_array_element array index = @Builtin_Method "Polyglot.read_array_element"
## Executes a polyglot function object (e.g. a lambda).
## Executes a polyglot function object (e.g. a lambda).
Arguments:
- callable: The polyglot function object to execute.
- arguments: A vector of arguments to callable.
execute : Any -> Vector -> Any
execute callable arguments = @Builtin_Method "Polyglot.execute"
Arguments:
- callable: The polyglot function object to execute.
- arguments: A vector of arguments to callable.
execute : Any -> Vector -> Any
execute callable arguments = @Builtin_Method "Polyglot.execute"
## Performs a by-name lookup for a member in a polyglot object.
## Performs a by-name lookup for a member in a polyglot object.
Arguments:
- object: The polyglot object on which to perform the member lookup.
- member_name: The textual name of the member to lookup.
Arguments:
- object: The polyglot object on which to perform the member lookup.
- member_name: The textual name of the member to lookup.
> Example
Look up the field a on an object o.
Polyglot.get_member o "a"
get_member : Any -> Text -> Any
get_member object member_name = @Builtin_Method "Polyglot.get_member"
> Example
Look up the field a on an object o.
Polyglot.get_member o "a"
get_member : Any -> Text -> Any
get_member object member_name = @Builtin_Method "Polyglot.get_member"
## Returns a polyglot array of all of the members of the provided object.
## Returns a polyglot array of all of the members of the provided object.
Arguments:
- object: The object from which to get a list of member names.
Arguments:
- object: The object from which to get a list of member names.
> Example
Get a list of the fields for an object o.
Polyglot.get_members o
get_members : Any -> Array
get_members object = @Builtin_Method "Polyglot.get_members"
> Example
Get a list of the fields for an object o.
Polyglot.get_members o
get_members : Any -> Array
get_members object = @Builtin_Method "Polyglot.get_members"
## Instantiates a polyglot object using the provided constructor.
## Instantiates a polyglot object using the provided constructor.
Arguments:
- constructor: The constructor with which to instantiate the object.
- arguments: A vector of the arguments to pass to the polyglot
constructor.
Arguments:
- constructor: The constructor with which to instantiate the object.
- arguments: A vector of the arguments to pass to the polyglot
constructor.
> Example
Instantiate a new Java Integer with the value 1.
Polyglot.new Integer [1]
new : Any -> Vector -> Any
new constructor arguments = @Builtin_Method "Polyglot.new"
> Example
Instantiate a new Java Integer with the value 1.
Polyglot.new Integer [1]
new : Any -> Vector -> Any
new constructor arguments = @Builtin_Method "Polyglot.new"
## Invokes a method on a polyglot object by name.
## Invokes a method on a polyglot object by name.
Arguments:
- target: The polyglot object on which to call the method.
- name: The name of the method.
- arguments: The arguments to pass to the method given by name.
invoke : Any -> Text -> Vector -> Any
invoke target name arguments = @Builtin_Method "Polyglot.invoke"
Arguments:
- target: The polyglot object on which to call the method.
- name: The name of the method.
- arguments: The arguments to pass to the method given by name.
invoke : Any -> Text -> Vector -> Any
invoke target name arguments = @Builtin_Method "Polyglot.invoke"
## ADVANCED
UNSTABLE
## ADVANCED
UNSTABLE
Checks if `value` defines a source location.
Checks if `value` defines a source location.
Source locations are typically exposed by functions, classes, sometimes
also other objects to specify their allocation sites.
has_source_location : Any -> Boolean
has_source_location value = @Builtin_Method "Polyglot.has_source_location"
Source locations are typically exposed by functions, classes, sometimes
also other objects to specify their allocation sites.
has_source_location : Any -> Boolean
has_source_location value = @Builtin_Method "Polyglot.has_source_location"
## ADVANCED
UNSTABLE
## ADVANCED
UNSTABLE
Gets the source location of `value`.
Gets the source location of `value`.
Source locations are typically exposed by functions, classes, sometimes
also other objects to specify their allocation sites.
This method will throw a polyglot exception if
`Polyglot.has_source_location value` returns `False`.
get_source_location : Any -> Source_Location
get_source_location value = @Builtin_Method "Polyglot.get_source_location"
Source locations are typically exposed by functions, classes, sometimes
also other objects to specify their allocation sites.
This method will throw a polyglot exception if
`Polyglot.has_source_location value` returns `False`.
get_source_location : Any -> Source_Location
get_source_location value = @Builtin_Method "Polyglot.get_source_location"
## Checks if a polyglot language is installed in the runtime environment.
## Checks if a polyglot language is installed in the runtime environment.
Arguments:
- langauge_name: The name of the language to test
is_language_installed : Text -> Boolean
is_language_installed language_name = @Builtin_Method "Polyglot.is_language_installed"
Arguments:
- langauge_name: The name of the language to test
is_language_installed : Text -> Boolean
is_language_installed language_name = @Builtin_Method "Polyglot.is_language_installed"
## ADVANCED
UNSTABLE
## ADVANCED
UNSTABLE
Returns the executable name of a polyglot object.
get_executable_name : Any -> Text
get_executable_name value = @Builtin_Method "Polyglot.get_executable_name"
Returns the executable name of a polyglot object.
get_executable_name : Any -> Text
get_executable_name value = @Builtin_Method "Polyglot.get_executable_name"
## Utilities for working with Java polyglot objects.
type Java
## Adds the provided entry to the host class path.
Arguments:
- path: The java classpath entry to add.
Use of the actual polyglot imports system should be preferred to use of
this method.
> Example
Adding Random to the classpath.
Java.add_to_class_path "java.util.Random"
add_to_class_path : Text -> Nothing
add_to_class_path path = @Builtin_Method "Java.add_to_class_path"
## Looks up a java symbol on the classpath by name.
Arguments:
- name: The name of the java symbol to look up.
Use of the actual polyglot imports system should be preferred to use of
this method.
> Example
Look up java's Random class.
Java.lookup_class "java.util.Random"
lookup_class : Text -> Any
lookup_class name = @Builtin_Method "Java.lookup_class"
## PRIVATE
Checks whether an object is an instance of a given class.
Arguments:
- object: The object to check for class membership.
- class: The java class to check for membership in.
is_instance : Any -> Any -> Boolean
is_instance object class =
class_object = class.class
class_object.isInstance object

View File

@ -1,48 +0,0 @@
## Utilities for working with Java polyglot objects.
import project.Any.Any
import project.Data.Boolean.Boolean
import project.Data.Text.Text
import project.Nothing.Nothing
## Adds the provided entry to the host class path.
Arguments:
- path: The java classpath entry to add.
Use of the actual polyglot imports system should be preferred to use of
this method.
> Example
Adding Random to the classpath.
Java.add_to_class_path "java.util.Random"
add_to_class_path : Text -> Nothing
add_to_class_path path = @Builtin_Method "Java.add_to_class_path"
## Looks up a java symbol on the classpath by name.
Arguments:
- name: The name of the java symbol to look up.
Use of the actual polyglot imports system should be preferred to use of
this method.
> Example
Look up java's Random class.
Java.lookup_class "java.util.Random"
lookup_class : Text -> Any
lookup_class name = @Builtin_Method "Java.lookup_class"
## PRIVATE
Checks whether an object is an instance of a given class.
Arguments:
- object: The object to check for class membership.
- class: The java class to check for membership in.
is_instance : Any -> Any -> Boolean
is_instance object class =
class_object = class.class
class_object.isInstance object

View File

@ -3,7 +3,7 @@ import project.Data.Array.Array
import project.Data.Text.Text
import project.Data.Vector.Vector
import project.Nothing.Nothing
import project.Polyglot
import project.Polyglot.Polyglot
import project.Runtime.Source_Location.Source_Location
from project.Data.Index_Sub_Range.Index_Sub_Range import First, Last

View File

@ -7,7 +7,7 @@ import project.Data.Pair.Pair
import project.Data.Vector.Vector
import project.Error.Error
import project.Nothing.Nothing
import project.Polyglot
import project.Polyglot.Polyglot
import project.Runtime
import project.Runtime.Source_Location.Source_Location
import project.Runtime.Stack_Trace_Element

View File

@ -6,51 +6,6 @@ import Standard.Table.Internal.Vector_Builder.Vector_Builder
import project.Data.SQL_Type.SQL_Type
import project.Data.SQL_Statement.SQL_Statement
## UNSTABLE
Creates a Builder representing and empty code fragment.
empty : Builder
empty = Builder.Value (Vector_Builder.empty)
## UNSTABLE
Creates a Builder representing a code fragment containing the specified raw
code.
Arguments:
- text: The raw SQL code.
code : Text -> Builder
code text =
vec = if text.is_empty then [] else [SQL_Fragment.Code_Part text]
Builder.Value (Vector_Builder.from_vector vec)
## UNSTABLE
Creates a Builder representing an interpolation of the given object.
Arguments:
- sql_type: The expected SQL type of `object`.
- object: The object to be interpolated into the query as if it has the type
given by `sql_type`.
interpolation : SQL_Type -> Any -> Builder
interpolation sql_type object = Builder.Value (Vector_Builder.from_vector [SQL_Fragment.Interpolation sql_type object])
## UNSTABLE
Joins a vector of code fragments with the provided separator.
Arguments:
- separator: The separator to use when joining the code fragments.
- statements: The SQL statements to join using `separator`.
join : Builder | Text -> Vector Builder -> Builder
join separator statements =
sep = case separator of
Builder.Value _ -> separator
_ -> code separator
if statements.length == 0 then empty else
(1.up_to statements.length . fold (statements.at 0) acc-> i-> acc ++ sep ++ statements.at i)
## UNSTABLE
A fragment of a SQL query.
@ -59,7 +14,6 @@ join separator statements =
SQL_Fragment.Interpolation which represents an object that will be
interpolated into the query.
type SQL_Fragment
## UNSTABLE
A SQL fragment that represents raw SQL code.
@ -80,6 +34,42 @@ type SQL_Fragment
Interpolation sql_type:SQL_Type object:Any
type Builder
## Creates a Builder representing and empty code fragment.
empty : Builder
empty = Builder.Value (Vector_Builder.empty)
## Creates a Builder representing a code fragment containing the specified raw
code.
Arguments:
- text: The raw SQL code.
code : Text -> Builder
code text =
vec = if text.is_empty then [] else [SQL_Fragment.Code_Part text]
Builder.Value (Vector_Builder.from_vector vec)
## Creates a Builder representing an interpolation of the given object.
Arguments:
- sql_type: The expected SQL type of `object`.
- object: The object to be interpolated into the query as if it has the type
given by `sql_type`.
interpolation : SQL_Type -> Any -> Builder
interpolation sql_type object = Builder.Value (Vector_Builder.from_vector [SQL_Fragment.Interpolation sql_type object])
## Joins a vector of code fragments with the provided separator.
Arguments:
- separator: The separator to use when joining the code fragments.
- statements: The SQL statements to join using `separator`.
join : Builder | Text -> Vector Builder -> Builder
join separator statements =
sep = case separator of
Builder.Value _ -> separator
_ -> Builder.code separator
if statements.length == 0 then Builder.empty else
(1.up_to statements.length . fold (statements.at 0) acc-> i-> acc ++ sep ++ statements.at i)
## PRIVATE
@ -100,7 +90,7 @@ type Builder
- other: The code fragment to append to `self`.
++ : Builder -> Builder
++ self other = case other of
text : Text -> if text == "" then self else Builder.Value (self.fragments ++ (code text).fragments)
text : Text -> if text == "" then self else Builder.Value (self.fragments ++ (Builder.code text).fragments)
_ -> Builder.Value (self.fragments ++ other.fragments)
## UNSTABLE
@ -121,7 +111,7 @@ type Builder
Wraps the code fragment in parentheses.
paren : Builder
paren self = code "(" ++ self ++ ")"
paren self = Builder.code "(" ++ self ++ ")"
## UNSTABLE
@ -135,7 +125,7 @@ type Builder
prefix_if_present self prefix =
pref = case prefix of
_ : Builder -> prefix
_ -> code prefix
_ -> Builder.code prefix
if self.is_empty then self else pref++self
## PRIVATE

View File

@ -1548,9 +1548,8 @@ type Table
Arguments:
- connection: The connection to a database.
- table_name: The name of the table to get.
- columns: The names of the columns to get.
- columns: List of columns to fetch. Each column is represented by a pair of column name and its expected SQL Type.
- ctx: The context to use for the table.
# make_table : Connection -> Text -> Vector [Text, SQL_Type] -> Context -> Table
make_table : Connection -> Text -> Vector -> Context -> Table
make_table connection table_name columns ctx =
if columns.is_empty then Error.throw (Illegal_State.Error "Unexpectedly attempting to create a Database Table with no columns. This is a bug in the Database library.") else

View File

@ -1,7 +1,6 @@
from Standard.Base import all
import Standard.Base.Errors.Illegal_State.Illegal_State
import project.Data.SQL
import project.Data.SQL.Builder
import project.Internal.IR.Context.Context
import project.Internal.IR.SQL_Expression.SQL_Expression
@ -10,7 +9,6 @@ import project.Internal.IR.SQL_Join_Kind.SQL_Join_Kind
import project.Internal.IR.Order_Descriptor.Order_Descriptor
import project.Internal.IR.Nulls_Order.Nulls_Order
import project.Internal.IR.Query.Query
from project.Data.SQL import code
from project.Errors import Unsupported_Database_Operation
@ -69,7 +67,7 @@ make_unary_op name =
arguments ->
case arguments.length == 1 of
True ->
(code name+" ")++(arguments.at 0) . paren
(Builder.code name+" ")++(arguments.at 0) . paren
False ->
Error.throw <| Illegal_State.Error ("Invalid amount of arguments for operation " + name)
@ -130,7 +128,7 @@ make_right_unary_op name =
make_function : Text -> (Vector Builder -> Builder)
make_function name =
arguments ->
(code name) ++ (SQL.join ", " arguments . paren)
(Builder.code name) ++ (Builder.join ", " arguments . paren)
## PRIVATE
@ -142,7 +140,7 @@ make_constant : Text -> (Vector Builder -> Builder)
make_constant sql_code =
arguments ->
if arguments.not_empty then Error.throw <| Illegal_State.Error "No arguments were expected" else
code sql_code
Builder.code sql_code
## PRIVATE
@ -157,7 +155,7 @@ make_constant sql_code =
wrap_in_quotes : Text -> Builder
wrap_in_quotes identifier =
escaped = identifier.replace '"' '""'
code '"'+escaped+'"'
Builder.code '"'+escaped+'"'
## PRIVATE
@ -197,7 +195,7 @@ make_iif arguments = case arguments.length of
expr = arguments.at 0
when_true = arguments.at 1
when_false = arguments.at 2
(code "CASE WHEN" ++ expr ++ " THEN " ++ when_true ++ " WHEN " ++ expr ++ " IS NULL THEN NULL ELSE " ++ when_false ++ " END").paren
(Builder.code "CASE WHEN" ++ expr ++ " THEN " ++ when_true ++ " WHEN " ++ expr ++ " IS NULL THEN NULL ELSE " ++ when_false ++ " END").paren
_ ->
Error.throw <| Illegal_State.Error ("Invalid amount of arguments for operation IIF")
@ -218,14 +216,14 @@ make_is_in arguments = case arguments.length of
0 -> Error.throw <| Illegal_State.Error ("The operation IS_IN requires at least one argument.")
## If only the self argument is provided, no value will ever be in the empty list, so we just short circuit to false.
`IN ()` would be more meaningful, but it is a syntax error.
1 -> code 'FALSE' . paren
1 -> Builder.code 'FALSE' . paren
_ ->
expr = arguments.first
list = arguments.drop 1
is_in = expr ++ " IN (" ++ (SQL.join ", " list) ++ ")"
is_in = expr ++ " IN (" ++ (Builder.join ", " list) ++ ")"
## We ensure that even `NULL IN (...)` is coalesced to False, so that
negation will work as expected.
code "COALESCE(" ++ is_in ++ ", FALSE)"
Builder.code "COALESCE(" ++ is_in ++ ", FALSE)"
## PRIVATE
make_is_in_column : Vector Builder -> Builder
@ -234,9 +232,9 @@ make_is_in_column arguments = case arguments.length of
expr = arguments.at 0
in_query = arguments.at 1
has_nulls_query = arguments.at 2
is_in = code "COALESCE(" ++ expr ++ " IN (" ++ in_query ++ "), FALSE)"
is_in = Builder.code "COALESCE(" ++ expr ++ " IN (" ++ in_query ++ "), FALSE)"
has_nulls = has_nulls_query.paren ++ " = TRUE"
code "CASE WHEN " ++ expr ++ " IS NULL THEN " ++ has_nulls ++ " ELSE " ++ is_in ++ " END"
Builder.code "CASE WHEN " ++ expr ++ " IS NULL THEN " ++ has_nulls ++ " ELSE " ++ is_in ++ " END"
_ -> Error.throw <| Illegal_State.Error ("The operation IS_IN_COLUMN requires at exactly 3 arguments: the expression, the IN subquery, the subquery checking for nulls.")
## PRIVATE
@ -250,7 +248,7 @@ generate_expression : Internal_Dialect -> SQL_Expression | Order_Descriptor | Qu
generate_expression dialect expr = case expr of
SQL_Expression.Column origin name ->
dialect.wrap_identifier origin ++ '.' ++ dialect.wrap_identifier name
SQL_Expression.Constant sql_type value -> SQL.interpolation sql_type value
SQL_Expression.Constant sql_type value -> Builder.interpolation sql_type value
SQL_Expression.Operation kind arguments ->
op = dialect.operation_map.get kind (Error.throw <| Unsupported_Database_Operation.Error kind)
parsed_args = arguments.map (generate_expression dialect)
@ -269,7 +267,7 @@ generate_expression dialect expr = case expr of
alias : Internal_Dialect -> Text -> Builder
alias dialect name =
wrapped = dialect.wrap_identifier name
code " AS " ++ wrapped
Builder.code " AS " ++ wrapped
## PRIVATE
@ -283,11 +281,11 @@ generate_from_part dialect from_spec = case from_spec of
From_Spec.Table name as_name ->
dialect.wrap_identifier name ++ alias dialect as_name
From_Spec.Query raw_sql as_name ->
code raw_sql . paren ++ alias dialect as_name
Builder.code raw_sql . paren ++ alias dialect as_name
From_Spec.Join kind left_spec right_spec on ->
left = generate_from_part dialect left_spec
right = generate_from_part dialect right_spec
ons = SQL.join " AND " (on.map (generate_expression dialect)) . prefix_if_present " ON "
ons = Builder.join " AND " (on.map (generate_expression dialect)) . prefix_if_present " ON "
left ++ (" " + kind.to_sql + " ") ++ right ++ ons
From_Spec.Sub_Query columns context as_name ->
sub = generate_query dialect (Query.Select columns context)
@ -295,7 +293,7 @@ generate_from_part dialect from_spec = case from_spec of
## PRIVATE
fold_case = lift_unary_op "FOLD_CASE" arg->
code "LOWER(UPPER(" ++ arg ++ "))"
Builder.code "LOWER(UPPER(" ++ arg ++ "))"
## PRIVATE
make_case_sensitive = lift_unary_op "MAKE_CASE_SENSITIVE" _->
@ -303,7 +301,7 @@ make_case_sensitive = lift_unary_op "MAKE_CASE_SENSITIVE" _->
## PRIVATE
simple_equals_ignore_case = Base_Generator.lift_binary_op "equals_ignore_case" a-> b->
code "LOWER(UPPER(" ++ a ++ ")) = LOWER(UPPER(" ++ b ++ "))"
Builder.code "LOWER(UPPER(" ++ a ++ ")) = LOWER(UPPER(" ++ b ++ "))"
## PRIVATE
make_equals a b =
@ -347,15 +345,15 @@ generate_select_context : Internal_Dialect -> Context -> Builder
generate_select_context dialect ctx =
gen_exprs exprs = exprs.map (generate_expression dialect)
from_part = generate_from_part dialect ctx.from_spec
where_part = (SQL.join " AND " (gen_exprs ctx.where_filters)) . prefix_if_present " WHERE "
group_part = (SQL.join ", " (gen_exprs ctx.groups)) . prefix_if_present " GROUP BY "
where_part = (Builder.join " AND " (gen_exprs ctx.where_filters)) . prefix_if_present " WHERE "
group_part = (Builder.join ", " (gen_exprs ctx.groups)) . prefix_if_present " GROUP BY "
limit_part = case ctx.limit of
Nothing -> ""
_ : Integer -> " LIMIT " + ctx.limit.to_text
orders = ctx.orders.map (generate_order dialect)
order_part = (SQL.join ", " orders) . prefix_if_present " ORDER BY "
(code " FROM ") ++ from_part ++ where_part ++ group_part ++ order_part ++ limit_part
order_part = (Builder.join ", " orders) . prefix_if_present " ORDER BY "
(Builder.code " FROM ") ++ from_part ++ where_part ++ group_part ++ order_part ++ limit_part
## PRIVATE
@ -368,11 +366,11 @@ generate_select_context dialect ctx =
expression returning a value.
generate_insert_query : Internal_Dialect -> Text -> Vector Any -> Builder
generate_insert_query dialect table_name pairs =
names = SQL.join ", " <| pairs.map (.first >> dialect.wrap_identifier)
values = SQL.join ", " <| pairs.map (.second >> generate_expression dialect)
names = Builder.join ", " <| pairs.map (.first >> dialect.wrap_identifier)
values = Builder.join ", " <| pairs.map (.second >> generate_expression dialect)
into = dialect.wrap_identifier table_name
code "INSERT INTO " ++ into ++ " (" ++ names ++ ") VALUES (" ++ values ++ ")"
Builder.code "INSERT INTO " ++ into ++ " (" ++ names ++ ") VALUES (" ++ values ++ ")"
## PRIVATE
@ -386,15 +384,15 @@ generate_query dialect query = case query of
Query.Select columns ctx ->
gen_column pair = (generate_expression dialect pair.second) ++ alias dialect pair.first
cols = case columns of
Nothing -> code "*"
_ -> SQL.join ", " (columns.map gen_column)
Nothing -> Builder.code "*"
_ -> Builder.join ", " (columns.map gen_column)
prefix = case ctx.distinct_on of
Nothing -> code ""
Nothing -> Builder.code ""
expressions : Vector ->
# TODO I just realised this does not make sense in other backends than Postgres, so we should probably fail in such cases; probably rewrite into a generic modifier? or a transform?
generated = SQL.join ", " (expressions.map (generate_expression dialect))
code "DISTINCT ON (" ++ generated ++ ") "
code "SELECT " ++ prefix ++ cols ++ generate_select_context dialect ctx
generated = Builder.join ", " (expressions.map (generate_expression dialect))
Builder.code "DISTINCT ON (" ++ generated ++ ") "
Builder.code "SELECT " ++ prefix ++ cols ++ generate_select_context dialect ctx
Query.Insert table_name pairs ->
generate_insert_query dialect table_name pairs
_ -> Error.throw <| Unsupported_Database_Operation.Error "Unsupported query type."
@ -437,10 +435,10 @@ make_concat make_raw_concat_expr make_contains_expr has_quote args =
includes_quote = make_contains_expr expr quote
is_empty = expr ++ " = ''"
needs_quoting = includes_separator.paren ++ " OR " ++ includes_quote.paren ++ " OR " ++ is_empty.paren
escaped = code "replace(" ++ expr ++ ", " ++ quote ++ ", " ++ quote ++ append ++ quote ++ ")"
escaped = Builder.code "replace(" ++ expr ++ ", " ++ quote ++ ", " ++ quote ++ append ++ quote ++ ")"
quoted = quote ++ append ++ escaped ++ append ++ quote
code "CASE WHEN " ++ needs_quoting ++ " THEN " ++ quoted ++ " ELSE " ++ expr ++ " END"
Builder.code "CASE WHEN " ++ needs_quoting ++ " THEN " ++ quoted ++ " ELSE " ++ expr ++ " END"
False -> expr
transformed_expr = code "CASE WHEN " ++ expr ++ " IS NULL THEN '' ELSE " ++ possibly_quoted.paren ++ " END"
transformed_expr = Builder.code "CASE WHEN " ++ expr ++ " IS NULL THEN '' ELSE " ++ possibly_quoted.paren ++ " END"
concatenated = make_raw_concat_expr transformed_expr separator
prefix.paren ++ append ++ concatenated ++ append ++ suffix.paren

View File

@ -78,6 +78,7 @@ type Join_Subquery_Setup
self.old_columns.zip self.new_columns old-> new->
[old.name, new]
## PRIVATE
prepare_subqueries : Table -> Table -> Boolean -> Boolean -> Pair Join_Subquery_Setup
prepare_subqueries left right needs_left_indicator needs_right_indicator =
## If a self-join, make sure we are able to distinguish the left and

View File

@ -5,7 +5,7 @@ import Standard.Base.Runtime.Managed_Resource.Managed_Resource
import Standard.Table.Data.Storage.Storage
import Standard.Table.Data.Table.Table as Materialized_Table
import project.Data.SQL
import project.Data.SQL.Builder
import project.Data.SQL_Statement.SQL_Statement
import project.Data.SQL_Type.SQL_Type
import project.Internal.Base_Generator
@ -195,8 +195,8 @@ create_table_statement name table temporary =
column_names = table.columns.map .name
col_makers = column_names.zip column_types name-> typ->
Base_Generator.wrap_in_quotes name ++ " " ++ typ.name
create_prefix = SQL.code <| if temporary then "CREATE TEMPORARY TABLE " else "CREATE TABLE "
(create_prefix ++ Base_Generator.wrap_in_quotes name ++ " (" ++ (SQL.join ", " col_makers) ++ ")").build
create_prefix = Builder.code <| if temporary then "CREATE TEMPORARY TABLE " else "CREATE TABLE "
(create_prefix ++ Base_Generator.wrap_in_quotes name ++ " (" ++ (Builder.join ", " col_makers) ++ ")").build
## PRIVATE
Returns the default database type corresponding to an in-memory storage type.

View File

@ -9,7 +9,7 @@ import Standard.Table.Internal.Problem_Builder.Problem_Builder
from Standard.Table.Data.Aggregate_Column.Aggregate_Column import all
import project.Connection.Connection.Connection
import project.Data.SQL
import project.Data.SQL.Builder
import project.Data.SQL_Statement.SQL_Statement
import project.Data.SQL_Type.SQL_Type
import project.Data.Table.Table
@ -25,7 +25,6 @@ import project.Internal.IR.Nulls_Order.Nulls_Order
import project.Internal.IR.SQL_Join_Kind.SQL_Join_Kind
import project.Internal.IR.Query.Query
from project.Data.SQL import code
from project.Errors import Unsupported_Database_Operation
## PRIVATE
@ -152,42 +151,43 @@ resolve_target_sql_type aggregate = case aggregate of
## PRIVATE
agg_count_is_null = Base_Generator.lift_unary_op "COUNT_IS_NULL" arg->
code "COUNT(CASE WHEN " ++ arg.paren ++ " IS NULL THEN 1 END)"
Builder.code "COUNT(CASE WHEN " ++ arg.paren ++ " IS NULL THEN 1 END)"
## PRIVATE
agg_count_empty = Base_Generator.lift_unary_op "COUNT_EMPTY" arg->
code "COUNT(CASE WHEN (" ++ arg.paren ++ " IS NULL) OR (" ++ arg.paren ++ " = '') THEN 1 END)"
Builder.code "COUNT(CASE WHEN (" ++ arg.paren ++ " IS NULL) OR (" ++ arg.paren ++ " = '') THEN 1 END)"
## PRIVATE
agg_count_not_empty = Base_Generator.lift_unary_op "COUNT_NOT_EMPTY" arg->
code "COUNT(CASE WHEN (" ++ arg.paren ++ " IS NOT NULL) AND (" ++ arg.paren ++ " != '') THEN 1 END)"
Builder.code "COUNT(CASE WHEN (" ++ arg.paren ++ " IS NOT NULL) AND (" ++ arg.paren ++ " != '') THEN 1 END)"
## PRIVATE
agg_median = Base_Generator.lift_unary_op "MEDIAN" arg->
median = code "percentile_cont(0.5) WITHIN GROUP (ORDER BY " ++ arg ++ ")"
median = Builder.code "percentile_cont(0.5) WITHIN GROUP (ORDER BY " ++ arg ++ ")"
## TODO Technically, this check may not be necessary if the input column has
type INTEGER, because it is impossible to represent a NaN in that type.
However, currently the column type inference is not tested well-enough to
rely on this, so leaving an uniform approach regardless of type. This
could be revisited when further work on column types takes place.
See issue: https://www.pivotaltracker.com/story/show/180854759
has_nan = code "bool_or(" ++ arg ++ " = double precision 'NaN')"
code "CASE WHEN " ++ has_nan ++ " THEN 'NaN' ELSE " ++ median ++ " END"
has_nan = Builder.code "bool_or(" ++ arg ++ " = double precision 'NaN')"
Builder.code "CASE WHEN " ++ has_nan ++ " THEN 'NaN' ELSE " ++ median ++ " END"
## PRIVATE
agg_mode = Base_Generator.lift_unary_op "MODE" arg->
code "mode() WITHIN GROUP (ORDER BY " ++ arg ++ ")"
Builder.code "mode() WITHIN GROUP (ORDER BY " ++ arg ++ ")"
## PRIVATE
agg_percentile = Base_Generator.lift_binary_op "PERCENTILE" p-> expr->
percentile = code "percentile_cont(" ++ p ++ ") WITHIN GROUP (ORDER BY " ++ expr ++ ")"
percentile = Builder.code "percentile_cont(" ++ p ++ ") WITHIN GROUP (ORDER BY " ++ expr ++ ")"
## TODO Technically, this check may not be necessary if the input column has
type INTEGER, because it is impossible to represent a NaN in that type.
However, currently the column type inference is not tested well-enough to
rely on this, so leaving an uniform approach regardless of type. This
could be revisited when further work on column types takes place.
See issue: https://www.pivotaltracker.com/story/show/180854759
has_nan = code "bool_or(" ++ expr ++ " = double precision 'NaN')"
code "CASE WHEN " ++ has_nan ++ " THEN 'NaN' ELSE " ++ percentile ++ " END"
has_nan = Builder.code "bool_or(" ++ expr ++ " = double precision 'NaN')"
Builder.code "CASE WHEN " ++ has_nan ++ " THEN 'NaN' ELSE " ++ percentile ++ " END"
## PRIVATE
These are written in a not most-efficient way, but a way that makes them
@ -200,36 +200,39 @@ first_last_aggregators =
last_not_null = make_first_aggregator reverse=True ignore_null=True
[["FIRST", first], ["FIRST_NOT_NULL", first_not_null], ["LAST", last], ["LAST_NOT_NULL", last_not_null]]
## PRIVATE
make_first_aggregator reverse ignore_null args =
if args.length < 2 then Error.throw (Illegal_State.Error "Insufficient number of arguments for the operation.") else
result_expr = args.first
order_bys = args.drop 1
filter_clause = if ignore_null.not then "" else
code " FILTER (WHERE " ++ result_expr.paren ++ " IS NOT NULL)"
Builder.code " FILTER (WHERE " ++ result_expr.paren ++ " IS NOT NULL)"
order_clause =
code " ORDER BY " ++ SQL.join "," order_bys
Builder.code " ORDER BY " ++ Builder.join "," order_bys
index_expr = case reverse of
True -> if ignore_null.not then "COUNT(*)" else
code "COUNT(" ++ result_expr ++ ")"
Builder.code "COUNT(" ++ result_expr ++ ")"
False -> "1"
code "(array_agg(" ++ result_expr.paren ++ order_clause ++ ")" ++ filter_clause ++ ")[" ++ index_expr ++ "]"
Builder.code "(array_agg(" ++ result_expr.paren ++ order_clause ++ ")" ++ filter_clause ++ ")[" ++ index_expr ++ "]"
## PRIVATE
agg_shortest = Base_Generator.lift_unary_op "SHORTEST" arg->
order_clause =
code " ORDER BY char_length(" ++ arg ++ ") ASC NULLS LAST"
code "(array_agg(" ++ arg.paren ++ order_clause ++ "))[1]"
Builder.code " ORDER BY char_length(" ++ arg ++ ") ASC NULLS LAST"
Builder.code "(array_agg(" ++ arg.paren ++ order_clause ++ "))[1]"
## PRIVATE
agg_longest = Base_Generator.lift_unary_op "LONGEST" arg->
order_clause =
code " ORDER BY char_length(" ++ arg ++ ") DESC NULLS LAST"
code "(array_agg(" ++ arg.paren ++ order_clause ++ "))[1]"
Builder.code " ORDER BY char_length(" ++ arg ++ ") DESC NULLS LAST"
Builder.code "(array_agg(" ++ arg.paren ++ order_clause ++ "))[1]"
## PRIVATE
concat_ops =
make_raw_concat_expr expr separator =
code "string_agg(" ++ expr ++ ", " ++ separator ++ ")"
Builder.code "string_agg(" ++ expr ++ ", " ++ separator ++ ")"
concat = Base_Generator.make_concat make_raw_concat_expr make_contains_expr
[["CONCAT", concat (has_quote=False)], ["CONCAT_QUOTE_IF_NEEDED", concat (has_quote=True)]]
@ -239,24 +242,24 @@ agg_count_distinct args = if args.is_empty then (Error.throw (Illegal_Argument.E
case args.length == 1 of
True ->
## A single null value will be skipped.
code "COUNT(DISTINCT " ++ args.first ++ ")"
Builder.code "COUNT(DISTINCT " ++ args.first ++ ")"
False ->
## A tuple of nulls is not a null, so it will not be skipped - but
we want to ignore all-null columns. So we manually filter them
out.
count = code "COUNT(DISTINCT (" ++ SQL.join ", " args ++ "))"
count = Builder.code "COUNT(DISTINCT (" ++ Builder.join ", " args ++ "))"
are_nulls = args.map arg-> arg.paren ++ " IS NULL"
all_nulls_filter = code " FILTER (WHERE NOT (" ++ SQL.join " AND " are_nulls ++ "))"
all_nulls_filter = Builder.code " FILTER (WHERE NOT (" ++ Builder.join " AND " are_nulls ++ "))"
(count ++ all_nulls_filter).paren
## PRIVATE
agg_count_distinct_include_null args =
## If we always count as tuples, then even null fields are counted.
code "COUNT(DISTINCT (" ++ SQL.join ", " args ++ ", 0))"
Builder.code "COUNT(DISTINCT (" ++ Builder.join ", " args ++ ", 0))"
## PRIVATE
starts_with = Base_Generator.lift_binary_op "starts_with" str-> sub->
res = code "starts_with(" ++ str ++ "," ++ sub ++ ")"
res = Builder.code "starts_with(" ++ str ++ "," ++ sub ++ ")"
res.paren
## PRIVATE
@ -266,11 +269,11 @@ ends_with = Base_Generator.lift_binary_op "ends_with" str-> sub->
## PRIVATE
make_case_sensitive = Base_Generator.lift_unary_op "MAKE_CASE_SENSITIVE" arg->
code "((" ++ arg ++ ') COLLATE "ucs_basic")'
Builder.code "((" ++ arg ++ ') COLLATE "ucs_basic")'
## PRIVATE
make_contains_expr expr substring =
code "position(" ++ substring ++ " in " ++ expr ++ ") > 0"
Builder.code "position(" ++ substring ++ " in " ++ expr ++ ") > 0"
## PRIVATE
contains = Base_Generator.lift_binary_op "contains" make_contains_expr
@ -305,11 +308,11 @@ is_nan = Base_Generator.lift_unary_op "IS_NAN" arg->
## PRIVATE
bool_or = Base_Generator.lift_unary_op "BOOL_OR" arg->
code "bool_or(" ++ arg ++ ")"
Builder.code "bool_or(" ++ arg ++ ")"
## PRIVATE
decimal_div = Base_Generator.lift_binary_op "/" x-> y->
code "CAST(" ++ x ++ " AS double precision) / CAST(" ++ y ++ " AS double precision)"
Builder.code "CAST(" ++ x ++ " AS double precision) / CAST(" ++ y ++ " AS double precision)"
## PRIVATE
mod_op = Base_Generator.lift_binary_op "mod" x-> y->

View File

@ -8,7 +8,7 @@ import Standard.Table.Internal.Problem_Builder.Problem_Builder
from Standard.Table.Data.Aggregate_Column.Aggregate_Column import all
import project.Connection.Connection.Connection
import project.Data.SQL
import project.Data.SQL.Builder
import project.Data.SQL_Statement.SQL_Statement
import project.Data.SQL_Type.SQL_Type
import project.Data.Table.Table
@ -22,7 +22,6 @@ import project.Internal.IR.Query.Query
import project.Internal.Common.Database_Distinct_Helper
import project.Internal.Common.Database_Join_Helper
from project.Data.SQL import code
from project.Errors import Unsupported_Database_Operation
## PRIVATE
@ -168,31 +167,31 @@ unsupported name =
## PRIVATE
agg_count_is_null = Base_Generator.lift_unary_op "COUNT_IS_NULL" arg->
code "COALESCE(SUM(" ++ arg.paren ++ " IS NULL), 0)"
Builder.code "COALESCE(SUM(" ++ arg.paren ++ " IS NULL), 0)"
## PRIVATE
agg_count_empty = Base_Generator.lift_unary_op "COUNT_EMPTY" arg->
code "COALESCE(SUM((" ++ arg.paren ++ " IS NULL) OR (" ++ arg.paren ++ " == '')), 0)"
Builder.code "COALESCE(SUM((" ++ arg.paren ++ " IS NULL) OR (" ++ arg.paren ++ " == '')), 0)"
## PRIVATE
agg_count_not_empty = Base_Generator.lift_unary_op "COUNT_NOT_EMPTY" arg->
code "COALESCE(SUM((" ++ arg.paren ++ " IS NOT NULL) AND (" ++ arg.paren ++ " != '')), 0)"
Builder.code "COALESCE(SUM((" ++ arg.paren ++ " IS NOT NULL) AND (" ++ arg.paren ++ " != '')), 0)"
## PRIVATE
agg_stddev_pop = Base_Generator.lift_unary_op "STDDEV_POP" arg->
sum_of_squares = code "SUM(" ++ arg.paren ++ "*" ++ arg.paren ++ ")"
square_of_sums = code "SUM(" ++ arg ++ ") * SUM(" ++ arg ++ ")"
n = code "CAST(COUNT(" ++ arg ++ ") AS REAL)"
var = code "(" ++ sum_of_squares ++ " - (" ++ square_of_sums ++ " / " ++ n ++ ")) / " ++ n
code "SQRT(" ++ var ++ ")"
sum_of_squares = Builder.code "SUM(" ++ arg.paren ++ "*" ++ arg.paren ++ ")"
square_of_sums = Builder.code "SUM(" ++ arg ++ ") * SUM(" ++ arg ++ ")"
n = Builder.code "CAST(COUNT(" ++ arg ++ ") AS REAL)"
var = Builder.code "(" ++ sum_of_squares ++ " - (" ++ square_of_sums ++ " / " ++ n ++ ")) / " ++ n
Builder.code "SQRT(" ++ var ++ ")"
## PRIVATE
agg_stddev_samp = Base_Generator.lift_unary_op "STDDEV_SAMP" arg->
sum_of_squares = code "SUM(" ++ arg.paren ++ "*" ++ arg.paren ++ ")"
square_of_sums = code "SUM(" ++ arg ++ ") * SUM(" ++ arg ++ ")"
n = code "CAST(COUNT(" ++ arg ++ ") AS REAL)"
var = code "(" ++ sum_of_squares ++ " - (" ++ square_of_sums ++ " / " ++ n ++ ")) / (" ++ n ++ " - 1)"
code "SQRT(" ++ var ++ ")"
sum_of_squares = Builder.code "SUM(" ++ arg.paren ++ "*" ++ arg.paren ++ ")"
square_of_sums = Builder.code "SUM(" ++ arg ++ ") * SUM(" ++ arg ++ ")"
n = Builder.code "CAST(COUNT(" ++ arg ++ ") AS REAL)"
var = Builder.code "(" ++ sum_of_squares ++ " - (" ++ square_of_sums ++ " / " ++ n ++ ")) / (" ++ n ++ " - 1)"
Builder.code "SQRT(" ++ var ++ ")"
## PRIVATE
This is a prototype that doesn't work correctly. Left for reference for
@ -212,30 +211,30 @@ window_aggregate window_type ignore_null args =
result_expr = args.first
order_exprs = args.drop 1
filter_clause = if ignore_null.not then code "" else
code " FILTER (WHERE " ++ result_expr.paren ++ " IS NOT NULL)"
filter_clause = if ignore_null.not then Builder.code "" else
Builder.code " FILTER (WHERE " ++ result_expr.paren ++ " IS NOT NULL)"
code window_type+"(" ++ result_expr ++ ")" ++ filter_clause ++ " OVER (ORDER BY " ++ SQL.join "," order_exprs ++ ")"
Builder.code window_type+"(" ++ result_expr ++ ")" ++ filter_clause ++ " OVER (ORDER BY " ++ Builder.join "," order_exprs ++ ")"
## PRIVATE
concat_ops =
make_raw_concat_expr expr separator =
code "group_concat(" ++ expr ++ ", " ++ separator ++ ")"
Builder.code "group_concat(" ++ expr ++ ", " ++ separator ++ ")"
concat = Base_Generator.make_concat make_raw_concat_expr make_contains_expr
[["CONCAT", concat (has_quote=False)], ["CONCAT_QUOTE_IF_NEEDED", concat (has_quote=True)]]
## PRIVATE
agg_count_distinct args = case args.length == 1 of
True -> code "COUNT(DISTINCT (" ++ args.first ++ "))"
True -> Builder.code "COUNT(DISTINCT (" ++ args.first ++ "))"
False -> Error.throw (Illegal_Argument.Error "COUNT_DISTINCT supports only single arguments in SQLite.")
## PRIVATE
agg_count_distinct_include_null args = case args.length == 1 of
True ->
arg = args.first
count = code "COUNT(DISTINCT " ++ arg ++ ")"
all_nulls_case = code "CASE WHEN COUNT(CASE WHEN " ++ arg ++ "IS NULL THEN 1 END) > 0 THEN 1 ELSE 0 END"
count = Builder.code "COUNT(DISTINCT " ++ arg ++ ")"
all_nulls_case = Builder.code "CASE WHEN COUNT(CASE WHEN " ++ arg ++ "IS NULL THEN 1 END) > 0 THEN 1 ELSE 0 END"
count ++ " + " ++ all_nulls_case
False -> Error.throw (Illegal_Argument.Error "COUNT_DISTINCT supports only single arguments in SQLite.")
@ -251,22 +250,22 @@ ends_with = Base_Generator.lift_binary_op "ends_with" str-> sub->
## PRIVATE
make_case_sensitive = Base_Generator.lift_unary_op "MAKE_CASE_SENSITIVE" arg->
code "((" ++ arg ++ ") COLLATE BINARY)"
Builder.code "((" ++ arg ++ ") COLLATE BINARY)"
## PRIVATE
make_contains_expr expr substring =
code "instr(" ++ expr ++ ", " ++ substring ++ ") > 0"
Builder.code "instr(" ++ expr ++ ", " ++ substring ++ ") > 0"
## PRIVATE
contains = Base_Generator.lift_binary_op "contains" make_contains_expr
## PRIVATE
bool_or = Base_Generator.lift_unary_op "BOOL_OR" arg->
code "max(" ++ arg ++ ")"
Builder.code "max(" ++ arg ++ ")"
## PRIVATE
decimal_div = Base_Generator.lift_binary_op "/" x-> y->
code "CAST(" ++ x ++ " AS REAL) / CAST(" ++ y ++ " AS REAL)"
Builder.code "CAST(" ++ x ++ " AS REAL) / CAST(" ++ y ++ " AS REAL)"
## PRIVATE
mod_op = Base_Generator.lift_binary_op "mod" x-> y->

View File

@ -3,7 +3,8 @@ import Standard.Base.Errors.Illegal_Argument.Illegal_Argument
import project.Data.Image.Image
## List comes from org.opencv.imgcodecs.Imgcodecs#imread doc comment.
## PRIVATE
List comes from org.opencv.imgcodecs.Imgcodecs#imread doc comment.
supported = [".bmp", ".dib", ".jpeg", ".jpg", ".jpe", ".jp2", ".png", ".webp", ".pbm", ".pgm", ".ppm", ".pxm", ".pnm", ".pfm", ".sr", ".ras", ".tiff", ".tif", ".exr", ".hdr", ".pic"]
## Read the file to a `Image` from a supported file format.

View File

@ -5,9 +5,9 @@ import Standard.Base.Errors.Unimplemented.Unimplemented
import project.Data.Table.Table
import project.Delimited.Delimited_Format.Delimited_Format
import project.Delimited.Delimited_Reader
import project.Delimited.Delimited_Writer
import project.Errors.Invalid_JSON_Format
import project.Internal.Delimited_Reader
import project.Internal.Delimited_Writer
Table.from (that : Text) (format:Delimited_Format = Delimited_Format.Delimited '\t') (on_problems:Problem_Behavior=Report_Warning) =
case format of

View File

@ -4,9 +4,9 @@ import Standard.Base.Network.HTTP.Response.Response
import project.Data.Table.Table
import project.Data.Data_Formatter.Data_Formatter
import project.Data.Match_Columns.Match_Columns
import project.Delimited.Delimited_Reader
import project.Delimited.Delimited_Writer
import project.Delimited.Quote_Style.Quote_Style
import project.Internal.Delimited_Reader
import project.Internal.Delimited_Writer
## Read delimited files such as CSVs into a Table.
type Delimited_Format

View File

@ -3,10 +3,10 @@ import Standard.Base.Errors.Illegal_Argument.Illegal_Argument
import project.Data.Table.Table
import project.Data.Match_Columns.Match_Columns
import project.Excel.Excel_Reader
import project.Excel.Excel_Workbook.Excel_Workbook
import project.Excel.Excel_Section.Excel_Section
import project.Excel.Excel_Writer
import project.Internal.Excel_Reader
import project.Internal.Excel_Writer
## PRIVATE
Resolve the xls_format setting to a boolean.

View File

@ -9,7 +9,7 @@ import Standard.Base.Metadata.Display
import project.Data.Table.Table
import project.Excel.Excel_Range.Excel_Range
import project.Excel.Excel_Reader
import project.Internal.Excel_Reader
polyglot java import org.enso.table.read.ExcelReader
polyglot java import org.apache.poi.ss.usermodel.Workbook

View File

@ -110,7 +110,8 @@ default_aggregate_column_name aggregate_column include_column=True =
c = aggregate_column.column
prefix + " " + (if include_column then c.name else "")
## Utility function to check if all same column
## PRIVATE
Utility function to check if all aggregates are operating on the same source column.
all_same_column : Vector Aggregate_Column -> Boolean
all_same_column aggregates =
is_not_count c = case c of

View File

@ -24,7 +24,8 @@ polyglot java import org.enso.table.parsing.TypeInferringParser
polyglot java import org.enso.table.read.QuoteStrippingParser
polyglot java import org.enso.table.parsing.problems.MismatchedQuote
## Reads a delimited file according to the provided format.
## PRIVATE
Reads a delimited file according to the provided format.
Arguments:
- format: The specification of the delimited file format.
@ -45,6 +46,7 @@ read_file format file on_problems =
result.catch Mismatched_Quote error->
Error.throw (File_Error.Corrupted_Format file error.to_display_text error)
## PRIVATE
read_text : Text -> Delimited_Format -> Problem_Behavior -> Table
read_text text format on_problems =
java_reader = StringReader.new text
@ -134,6 +136,7 @@ type Detected_Headers
## Indicates that the file exists but no headers have been found, so only positional column matching is possible.
None (column_count : Integer)
## PRIVATE
type Detected_File_Metadata
## PRIVATE
An internal type representing metadata describing the format of a specific

View File

@ -9,8 +9,8 @@ import project.Data.Match_Columns.Match_Columns
import project.Data.Storage.Storage
import project.Delimited.Delimited_Format.Delimited_Format
import project.Delimited.Quote_Style.Quote_Style
import project.Delimited.Delimited_Reader
import project.Delimited.Delimited_Reader.Detected_Headers
import project.Internal.Delimited_Reader
import project.Internal.Delimited_Reader.Detected_Headers
import project.Internal.Java_Problems
from project.Errors import Column_Count_Mismatch, Column_Name_Mismatch
@ -24,7 +24,8 @@ polyglot java import java.io.StringWriter
polyglot java import java.io.IOException
polyglot java import java.io.Writer
## Writes a delimited file according to the provided format.
## PRIVATE
Writes a delimited file according to the provided format.
Arguments:
- table: The table to serialize.

View File

@ -30,8 +30,7 @@ prepare_reader_table on_problems result_with_problems =
## PRIVATE
Convert Boolean|Infer to the correct HeaderBehavior
# TODO[DB] Fix composite types #183857386
# make_java_headers : (Boolean | Infer) -> ExcelHeaders.HeaderBehavior
make_java_headers : (Boolean | Infer) -> ExcelHeaders.HeaderBehavior
make_java_headers headers = case headers of
True -> ExcelHeaders.HeaderBehavior.USE_FIRST_ROW_AS_HEADERS
Infer -> ExcelHeaders.HeaderBehavior.INFER

View File

@ -6,7 +6,7 @@ import project.Data.Table.Table
import project.Data.Match_Columns.Match_Columns
import project.Excel.Excel_Range.Excel_Range
import project.Excel.Excel_Section.Excel_Section
import project.Excel.Excel_Reader
import project.Internal.Excel_Reader
from project.Errors import Invalid_Location, Range_Exceeded, Existing_Data, Column_Count_Mismatch, Column_Name_Mismatch
polyglot java import org.enso.table.read.ExcelReader

View File

@ -1,7 +1,6 @@
from Standard.Base import all
## UNSTABLE
## PRIVATE
A function that throws an error to indicate that a file is being uploaded to
`path`.

View File

@ -143,6 +143,8 @@ Vector.default_visualization self = Id.table
Vector.to_default_visualization_data : Text
Vector.to_default_visualization_data self = render_vector self
## PRIVATE
Internal function to convert a Vector to a JSON string.
render_vector object depth=0 max_depth=5 max_length=100 =
case object of
_ : Vector -> if depth == max_depth then "[...]" else

View File

@ -36,7 +36,8 @@ type Table_Update
Json.from_pairs [chunks, table_specification_update]
## Return a sub-window of a table. The window is defined by a cell row/col and line/chunk
## PRIVATE
Return a sub-window of a table. The window is defined by a cell row/col and line/chunk
coordinate as origin and the extent of the window in text chunks and lines. The size of
a chunk (the characters in it) is defined by `chunk_width`. The output is formatted as a message
that can be sent to the IDE's lazy text visualisation.
@ -88,7 +89,8 @@ compute_table_update table table_cell_position text_window_position text_window_
layout = Table_Specification_Update.Value row_heights column_widths column_names []
Table_Update.Value chunks layout
## Returns a vector that contains a pairs of row index and vector of corresponding lines indices.
## PRIVATE
Returns a vector that contains a pairs of row index and vector of corresponding lines indices.
compute_vertical_indices table start_row end_row start_line lines_to_get =
## agg is a Vector of `[processed_lines, initial_offset, result_indices]`
process_line agg row_ix =
@ -114,7 +116,8 @@ compute_vertical_indices table start_row end_row start_line lines_to_get =
result_agg = row_ix_iter.to_vector.fold agg process_line
result_agg.get 2 . flatten
## Compute the text chunks for the row/line defined by the given indices limited to the given
## PRIVATE
Compute the text chunks for the row/line defined by the given indices limited to the given
column indices. The number of chunks to get is defined by `chunks_to_get`.
get_chunks_for_row table row_ix line_ix initial_chunk_offset column_range chunk_size chunks_to_get =
process_cell agg column_ix =
@ -136,27 +139,32 @@ get_chunks_for_row table row_ix line_ix initial_chunk_offset column_range chunk_
if column_indices == [] then [] else
(fold_map [0, initial_chunk_offset] process_cell column_indices).flatten
## Return the max value in the given vector.
## PRIVATE
Return the max value in the given vector.
max : Vector Integer -> Integer
max vector =
vector.fold 0 (l -> r -> Math.max l r)
## Return the longest line in the given text.
## PRIVATE
Return the longest line in the given text.
get_longest_line : Text -> Integer
get_longest_line text =
max (text.lines.map (line -> line.length))
## Return the length of the longest line in the given column.
## PRIVATE
Return the length of the longest line in the given column.
get_column_width column =
max (column.to_vector.map (x -> get_longest_line x.to_text))
## Return the height of the row defined by the given index.
## PRIVATE
Return the height of the row defined by the given index.
get_row_height table row_ix =
columns = table.columns
row = columns.map (column -> column.at row_ix)
max (row.map (x -> x.to_text.lines.length))
## Return the index of the first item in the given vector that brings the cummulative sum of items
## PRIVATE
Return the index of the first item in the given vector that brings the cummulative sum of items
above the target value. If no such item exists, return `Nothing`.
find_first_over_cum_sum : Vector Integer -> Integer -> Integer | Nothing
find_first_over_cum_sum items target =
@ -166,7 +174,8 @@ find_first_over_cum_sum items target =
Not_Found -> Nothing
value -> value.get 0
## Return the index of the column that is at the end of the given text width, when starting from the
## PRIVATE
Return the index of the column that is at the end of the given text width, when starting from the
given start column index.
find_end_column table start_column_ix chunks chunk_size =
table_columns_count = table.columns.length
@ -178,7 +187,8 @@ find_end_column table start_column_ix chunks chunk_size =
Nothing -> table_columns_count - 1
value -> value + start_column_ix
## Return the index of the row that is at the end of the given text height, when starting from the
## PRIVATE
Return the index of the row that is at the end of the given text height, when starting from the
given start row index.
find_end_row table start_row_ix max_height =
table_row_count = (table.columns.get 0).length
@ -189,7 +199,8 @@ find_end_row table start_row_ix max_height =
Nothing -> table_row_count - 1
value -> value + start_row_ix
## Helper for fold_map that takes a function, an accumulator value and the current item and returns
## PRIVATE
Helper for fold_map that takes a function, an accumulator value and the current item and returns
a tuple of the new accumulator value and the result of the function.
fold_map_inner f acc item =
previous_mappings = acc.first
@ -200,20 +211,23 @@ fold_map_inner f acc item =
new_mappings = previous_mappings + [current_mapping]
Pair.new new_mappings new_acc_value
## Map a function over a vectors, but also pass on a accumulator value from one step to the next.
The function must return a tuple of the result of the function and the new accumulator value.
## PRIVATE
Map a function over a vectors, but also pass on a accumulator value from one step to the next.
The function must return a tuple of the result of the function and the new accumulator value.
fold_map acc f iterable =
result = iterable.fold (Pair.new [] acc) (fold_map_inner f)
result.first
## Return a vector of the cumulative sum of the given vector.
## PRIVATE
Return a vector of the cumulative sum of the given vector.
map_to_cumulative_sum iterable =
map_running_sums previous_sum current =
running_sum = previous_sum + current
[running_sum, running_sum]
fold_map 0 map_running_sums iterable
## Return the given vector where each item is mapped to itself and its index in the vector.
## PRIVATE
Return the given vector where each item is mapped to itself and its index in the vector.
enumerate : Vector Any -> Vector Any
enumerate vector =
(0.up_to vector.length).to_vector.zip vector

View File

@ -3,7 +3,6 @@ from Standard.Base import all
from Standard.Base.Data.Text.Extensions import slice_text
## PRIVATE
Message to be sent to the IDE.
type Message
@ -19,7 +18,8 @@ type Message
max_line_length = ["longest_line", self.max_line_length]
Json.from_pairs [chunks, line_count, max_line_length]
## Return a sub-window of a string. The window is defined by line/chunk coordinates. The size of
## PRIVATE
Return a sub-window of a string. The window is defined by line/chunk coordinates. The size of
a chunk is defined by `chunk_width`. The output is formatted as a message that can be sent to
the IDE's lazy text visualisation.
get_lazy_visualisation_text_window text pos size chunk_width =

View File

@ -112,12 +112,13 @@ class PolyglotTest extends InterpreterTest {
"fail to match on Polyglot symbol when imported everything from stdlib" in {
val code =
"""from Standard.Base import all
|import Standard.Base.Polyglot as Polyglot_Module
|polyglot java import java.util.Random
|
|main =
| random_gen = Random.new
| case random_gen of
| Polyglot -> IO.println "OK"
| Polyglot_Module -> IO.println "OK"
| _ -> IO.println "FAIL"
|""".stripMargin
eval(code)
@ -127,7 +128,7 @@ class PolyglotTest extends InterpreterTest {
"match on Polyglot type when explicitly importing everything from Polyglot module" in {
val code =
"""from Standard.Base.Polyglot import all
"""import Standard.Base.Polyglot.Polyglot
|import Standard.Base.IO
|polyglot java import java.util.Random
|

View File

@ -110,10 +110,10 @@ spec = Test.group "Pattern Matches" <|
Test.specify "should be able to match on the Polyglot type" <|
random_gen = Random.new
case random_gen of
Polyglot.Polyglot -> Nothing
Polyglot -> Nothing
_ -> Test.fail "Expected a polyglot object to match."
case Polyglot.Polyglot of
Polyglot.Polyglot -> Nothing
case Polyglot of
Polyglot -> Nothing
_ -> Test.fail "Expected the Polyglot constructor to match."
Test.specify "should be able to match on the Any type" <|
value_1 = 1.23143

View File

@ -1,5 +1,4 @@
polyglot java import java.time.LocalDate
import project.Polyglot
new year (month = 1) (day = 1) = (LocalDate.of year month day) . internal_local_date

View File

@ -31,12 +31,12 @@ from project.Data.Numbers export Number, Integer
import project.Data.Vector.Vector
export project.Data.Vector.Vector
import project.Polyglot
export project.Polyglot
import project.Polyglot.Java
export project.Polyglot.Java
import project.Polyglot.Polyglot
export project.Polyglot.Polyglot
import project.Runtime
export project.Runtime

View File

@ -1,13 +1,15 @@
@Builtin_Type
type Polyglot
get_array_size array = @Builtin_Method "Polyglot.get_array_size"
execute callable arguments = @Builtin_Method "Polyglot.execute"
get_member object member_name = @Builtin_Method "Polyglot.get_member"
get_members object = @Builtin_Method "Polyglot.get_members"
new constructor arguments = @Builtin_Method "Polyglot.new"
invoke target name arguments = @Builtin_Method "Polyglot.invoke"
has_source_location value = @Builtin_Method "Polyglot.has_source_location"
get_source_location value = @Builtin_Method "Polyglot.get_source_location"
is_language_installed language_name = @Builtin_Method "Polyglot.is_language_installed"
get_executable_name = @Builtin_Method "Polyglot.get_executable_name"
get_array_size array = @Builtin_Method "Polyglot.get_array_size"
execute callable arguments = @Builtin_Method "Polyglot.execute"
get_member object member_name = @Builtin_Method "Polyglot.get_member"
get_members object = @Builtin_Method "Polyglot.get_members"
new constructor arguments = @Builtin_Method "Polyglot.new"
invoke target name arguments = @Builtin_Method "Polyglot.invoke"
has_source_location value = @Builtin_Method "Polyglot.has_source_location"
get_source_location value = @Builtin_Method "Polyglot.get_source_location"
is_language_installed language_name = @Builtin_Method "Polyglot.is_language_installed"
get_executable_name = @Builtin_Method "Polyglot.get_executable_name"
type Java
lookup_class name = @Builtin_Method "Java.lookup_class"

View File

@ -1 +0,0 @@
lookup_class name = @Builtin_Method "Java.lookup_class"