Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DO NOT MERGE] Draft of PartiQL SPI factoring for functions #1332

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion partiql-spi/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ plugins {
}

dependencies {
api(Deps.ionElement)
api(project(":partiql-types"))
}

Expand Down
11 changes: 7 additions & 4 deletions partiql-spi/src/main/kotlin/org/partiql/spi/BindingName.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@ package org.partiql.spi
/**
* Encapsulates the data necessary to perform a binding lookup.
*/
public data class BindingName(val name: String, val bindingCase: BindingCase) {
val loweredName: String by lazy(LazyThreadSafetyMode.PUBLICATION) { name.lowercase() }
public data class BindingName(
public val name: String,
public val case: BindingCase,
) {

/**
* Compares [name] to [otherName] using the rules specified by [bindingCase].
* Compares [name] to [otherName] using the rules specified by [case].
*/
public fun isEquivalentTo(otherName: String?): Boolean = otherName != null && name.isBindingNameEquivalent(otherName, bindingCase)
public fun isEquivalentTo(otherName: String?): Boolean =
otherName != null && name.isBindingNameEquivalent(otherName, case)

/**
* Compares this string to [other] using the rules specified by [case].
Expand Down
9 changes: 6 additions & 3 deletions partiql-spi/src/main/kotlin/org/partiql/spi/BindingPath.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

package org.partiql.spi

public data class BindingPath(
val steps: List<BindingName>
)
/**
* A [BindingPath] represents an SQL-qualified identifier which is composed of case-sensitive and case-insensitive steps.
*
* @property steps
*/
public data class BindingPath(public val steps: List<BindingName>)
10 changes: 1 addition & 9 deletions partiql-spi/src/main/kotlin/org/partiql/spi/Plugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,14 @@
package org.partiql.spi

import org.partiql.spi.connector.Connector
import org.partiql.spi.function.PartiQLFunction
import org.partiql.spi.function.PartiQLFunctionExperimental

/**
* A singular unit of external logic.
* A plugin provides a [Connector] implementation for a catalog of the PartiQL system.
*/
public interface Plugin {

/**
* A [Connector.Factory] is used to instantiate a connector.
*/
public val factory: Connector.Factory

/**
* Functions defined by this plugin.
*/
@PartiQLFunctionExperimental
public val functions: List<PartiQLFunction>
}
25 changes: 21 additions & 4 deletions partiql-spi/src/main/kotlin/org/partiql/spi/connector/Connector.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@

package org.partiql.spi.connector

import com.amazon.ionelement.api.StructElement
import org.partiql.value.PartiQLValue
import org.partiql.value.PartiQLValueExperimental
import org.partiql.value.StructValue

/**
* A mechanism by which PartiQL can access a Catalog.
Expand All @@ -30,6 +32,20 @@ public interface Connector {
*/
public fun getMetadata(session: ConnectorSession): ConnectorMetadata

/**
* Returns a [ConnectorBindings] which the engine uses to load values.
*
* @return
*/
public fun getBindings(): ConnectorBindings

/**
* Returns a [ConnectorFunctions] which the engine uses to load user-defined-function implementations.
*
* @return
*/
public fun getFunctions(): ConnectorFunctions

/**
* A Plugin leverages a [Factory] to produce a [Connector] which is used for catalog metadata and data access.
*/
Expand All @@ -43,10 +59,11 @@ public interface Connector {
/**
* The connector factory method.
*
* @param catalogName
* @param config
* @param catalogName The name of the catalog to be backed by this [Connector] instance.
* @param config Configuration
* @return
*/
public fun create(catalogName: String, config: StructElement? = null): Connector
@OptIn(PartiQLValueExperimental::class)
public fun create(catalogName: String, config: StructValue<PartiQLValue>? = null): Connector
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@

package org.partiql.spi.connector

public object Constants {
public const val CONFIG_KEY_CONNECTOR_NAME: String = "connector_name"
import org.partiql.value.PartiQLValue
import org.partiql.value.PartiQLValueExperimental

@OptIn(PartiQLValueExperimental::class)
public interface ConnectorBindings {

public fun getValue(path: ConnectorPath): PartiQLValue
rchowell marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package org.partiql.spi.function
package org.partiql.spi.connector

import org.partiql.types.function.FunctionSignature
import org.partiql.value.PartiQLValue
import org.partiql.value.PartiQLValueExperimental

/**
* The [PartiQLFunction] interface is used to implement user-defined-functions (UDFs).
* The [ConnectorFunction] interface is used to implement user-defined-functions (UDFs).
* UDFs can be registered to a plugin for use in the query planner and evaluator.
*/
@PartiQLFunctionExperimental
public sealed interface PartiQLFunction {
@ConnectorFunctionExperimental
public sealed interface ConnectorFunction {

/**
* Defines the function's parameters and argument handling.
Expand All @@ -19,7 +19,7 @@ public sealed interface PartiQLFunction {
/**
* Represents an SQL row-value expression call.
*/
public interface Scalar : PartiQLFunction {
public interface Scalar : ConnectorFunction {

/**
* Scalar function signature.
Expand All @@ -39,7 +39,7 @@ public sealed interface PartiQLFunction {
/**
* Represents an SQL table-value expression call.
*/
public interface Aggregation : PartiQLFunction {
public interface Aggregation : ConnectorFunction {

/**
* Aggregation function signature.
Expand Down Expand Up @@ -73,4 +73,4 @@ public sealed interface PartiQLFunction {
@OptIn(PartiQLValueExperimental::class)
public fun value(): PartiQLValue
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.partiql.spi.connector

@RequiresOptIn(
message = "ConnectorFunction requires explicit opt-in",
level = RequiresOptIn.Level.ERROR,
)
public annotation class ConnectorFunctionExperimental
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.partiql.spi.connector

import org.partiql.types.function.FunctionSignature

/**
* A [ConnectorFunctionHandle] represents the location and typing information for a [ConnectorFunction].
*/
public sealed interface ConnectorFunctionHandle {

/**
* The absolute path to this function's definition in the catalog.
*/
public val path: ConnectorPath

/**
* The function's type definition.
*/
public val signature: FunctionSignature

/**
* Handle to a scalar function.
*
* @property path
* @property signature
*/
public data class Scalar(
override val path: ConnectorPath,
override val signature: FunctionSignature.Scalar,
) : ConnectorFunctionHandle

/**
* Handle to an aggregation function.
*
* @property path
* @property signature
*/
public data class Aggregation(
override val path: ConnectorPath,
override val signature: FunctionSignature.Aggregation,
) : ConnectorFunctionHandle
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.partiql.spi.connector

/**
* A [ConnectorFunctions] implementation is responsible for linking a handle to a function implementation for execution.
*/
@ConnectorFunctionExperimental
public interface ConnectorFunctions {

public fun getScalarFunction(handle: ConnectorFunctionHandle.Scalar): ConnectorFunction.Scalar

public fun getAggregationFunction(handle: ConnectorFunctionHandle.Aggregation): ConnectorFunction.Aggregation
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,17 @@ package org.partiql.spi.connector

import org.partiql.spi.BindingPath
import org.partiql.types.StaticType
import org.partiql.types.function.FunctionSignature

/**
* Aids in retrieving relevant Catalog metadata for the purpose of planning and execution.
*/
public interface ConnectorMetadata {

/**
* Scalar function signatures available via call syntax.
*/
public val functions: List<FunctionSignature.Scalar>
get() = emptyList()

/**
* Scalar function signatures available via operator or special form syntax.
*/
public val operators: List<FunctionSignature.Scalar>
get() = emptyList()

/**
* Aggregation function signatures.
*/
public val aggregations: List<FunctionSignature.Aggregation>
get() = emptyList()

/**
* Returns the descriptor of an object. If the handle is unable to produce a [StaticType], implementers should
* return null.
*/
public fun getObjectType(session: ConnectorSession, handle: ConnectorObjectHandle): StaticType?
public fun getObjectType(handle: ConnectorObjectHandle): StaticType?

/**
* Given a [BindingPath], returns a [ConnectorObjectHandle] that corresponds to the longest-available requested path.
Expand All @@ -56,10 +37,55 @@ public interface ConnectorMetadata {
* As another example, consider an object within a Namespace that may be a Struct with nested attributes. A user could
* call [getObjectHandle] with the [path] of "a"."b"."c"."Object"."x". In the Namespace, only object "Object" exists.
* Therefore, this method will return a [ConnectorObjectHandle] with the "Object" representation and the matching
* path: "a"."b"."c"."Object". The returned [ConnectorObjectHandle.absolutePath] must be correct for correct
* path: "a"."b"."c"."Object". The returned [ConnectorObjectHandle.path] must be correct for correct
* evaluation.
*
* If the [path] does not correspond to an existing [ConnectorObject], implementers should return null.
*/
public fun getObjectHandle(session: ConnectorSession, path: BindingPath): ConnectorObjectHandle?
public fun getObjectHandle(path: BindingPath): ConnectorObjectHandle?
johnedquinn marked this conversation as resolved.
Show resolved Hide resolved

/**
* Returns a list of scalar functions at the given path.
*
* @param path
rchowell marked this conversation as resolved.
Show resolved Hide resolved
* @return
*/
public fun getScalarFunctions(path: BindingPath): List<ConnectorFunctionHandle.Scalar>

/**
* Returns a list of scalar operators at the given path.
*
* @param path
* @return
*/
public fun getScalarOperators(path: BindingPath): List<ConnectorFunctionHandle.Scalar>

/**
* Returns a list of aggregation functions at the given path.
*
* @param session
* @param path
* @return
*/
public fun getAggregationFunctions(
session: ConnectorSession,
johnedquinn marked this conversation as resolved.
Show resolved Hide resolved
path: BindingPath,
): List<ConnectorFunctionHandle.Aggregation>

/**
* A base implementation of ConnectorMetadata for use in Java as the generated interface DefaultImpls is final.
*/
public abstract class Base : ConnectorMetadata {

override fun getScalarFunctions(path: BindingPath): List<ConnectorFunctionHandle.Scalar> =
emptyList()

override fun getScalarOperators(path: BindingPath): List<ConnectorFunctionHandle.Scalar> =
emptyList()

override fun getAggregationFunctions(
session: ConnectorSession,
path: BindingPath,
): List<ConnectorFunctionHandle.Aggregation> = emptyList()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@
package org.partiql.spi.connector

/**
* Holds a PartiQL Value's representation within a Catalog and its location within the Catalog.
* Holds a Catalog and its location within the Catalog.
*
* @property path The absolute path to this object in the catalog
* @property obj Arbitrary metadata associated with this object.
*/
public class ConnectorObjectHandle(
public val absolutePath: ConnectorObjectPath,
public val value: ConnectorObject
public val path: ConnectorPath,
public val obj: ConnectorObject,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the need of a separate ConnectorObject interface, if this is just going to be holding metadata.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConnectorObject is for arbitrary metadata about a catalog's values. ConnectorFunctionHandle is only for function metadata

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see your question is actually slightly different.

ConnectorObject is not analogous to ConnectorFunction. ConnectorObject would be better named as ConnectorObjectMetadata. It is most similar to FunctionSignature, but can be anything.

)
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,4 @@ package org.partiql.spi.connector
/**
* The path to an object within the current Catalog.
*/
public data class ConnectorObjectPath(
val steps: List<String>
)
public data class ConnectorPath(public val steps: List<String>)
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ package org.partiql.spi.connector
* Session details that are exposed to plugin implementers.
*/
public interface ConnectorSession {
public fun getQueryId(): String
public fun getUserId(): String
public val queryId: String
public val userId: String
}

This file was deleted.

Loading