-
Notifications
You must be signed in to change notification settings - Fork 62
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Updates catalog names for case-insensitive lookup
- Loading branch information
Showing
8 changed files
with
393 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
partiql-planner/src/main/kotlin/org/partiql/planner/catalog/Catalogs.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package org.partiql.planner.catalog | ||
|
||
/** | ||
* Catalogs is used to provide the default catalog and possibly others by name. | ||
*/ | ||
public interface Catalogs { | ||
|
||
/** | ||
* Returns the default catalog. Required. | ||
*/ | ||
public fun default(): Catalog | ||
|
||
/** | ||
* Returns a catalog by name (single identifier). | ||
*/ | ||
public fun get(name: String, ignoreCase: Boolean = false): Catalog? { | ||
val default = default() | ||
return if (name.equals(default.getName(), ignoreCase)) { | ||
default | ||
} else { | ||
null | ||
} | ||
} | ||
|
||
/** | ||
* Returns a list of all available catalogs. | ||
*/ | ||
public fun list(): Collection<Catalog> = listOf(default()) | ||
} |
173 changes: 173 additions & 0 deletions
173
partiql-planner/src/main/kotlin/org/partiql/planner/catalog/Identifier.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
package org.partiql.planner.catalog | ||
|
||
/** | ||
* Represents an SQL identifier (possibly qualified). | ||
* | ||
* @property qualifier If | ||
* @property identifier | ||
*/ | ||
public class Identifier private constructor( | ||
private val qualifier: Array<Part>, | ||
private val identifier: Part, | ||
) { | ||
|
||
/** | ||
* Returns the unqualified name part. | ||
*/ | ||
public fun getIdentifier(): Part = identifier | ||
|
||
/** | ||
* Returns the name's namespace. | ||
*/ | ||
public fun getQualifier(): Array<Part> = qualifier | ||
|
||
/** | ||
* Returns true if the namespace is non-empty. | ||
*/ | ||
public fun hasQualifier(): Boolean = qualifier.isNotEmpty() | ||
|
||
/** | ||
* Compares one identifier to another, possibly ignoring case. | ||
*/ | ||
public fun matches(other: Identifier, ignoreCase: Boolean = false): Boolean { | ||
// | ||
if (this.qualifier.size != other.qualifier.size) { | ||
return false | ||
} | ||
// Compare identifier | ||
if (ignoreCase && !(this.identifier.matches(other.identifier))) { | ||
return false | ||
} else if (this.identifier != other.identifier) { | ||
return false | ||
} | ||
for (i in this.qualifier.indices) { | ||
val lhs = this.qualifier[i] | ||
val rhs = other.qualifier[i] | ||
if (ignoreCase && !lhs.matches(rhs)) { | ||
return false | ||
} else if (lhs != rhs) { | ||
return false | ||
} | ||
} | ||
return true | ||
} | ||
|
||
/** | ||
* Compares the case-preserved text of two identifiers — that is case-sensitive equality. | ||
*/ | ||
public override fun equals(other: Any?): Boolean { | ||
if (this === other) { | ||
return true | ||
} | ||
if (other == null || javaClass != other.javaClass) { | ||
return false | ||
} | ||
other as Identifier | ||
return (this.identifier == other.identifier && this.qualifier.contentEquals(other.qualifier)) | ||
} | ||
|
||
/** | ||
* The hashCode() is case-sensitive — java.util.Arrays.hashCode | ||
*/ | ||
public override fun hashCode(): Int { | ||
var result = 1 | ||
result = 31 * result + qualifier.hashCode() | ||
result = 31 * result + identifier.hashCode() | ||
return result | ||
} | ||
|
||
/** | ||
* Return the SQL representation of this identifier. | ||
*/ | ||
public override fun toString(): String = buildString { | ||
if (qualifier.isNotEmpty()) { | ||
append(qualifier.joinToString(".")) | ||
append(".") | ||
} | ||
append(identifier) | ||
} | ||
|
||
/** | ||
* Represents an SQL identifier part which is either regular (unquoted) or delimited (double-quoted). | ||
* | ||
* @property text The case-preserved identifier text. | ||
* @property regular True if the identifier should be treated as an SQL regular identifier. | ||
*/ | ||
public class Part private constructor( | ||
private val text: String, | ||
private val regular: Boolean, | ||
) { | ||
|
||
/** | ||
* Compares two identifiers, ignoring case iff at least one identifier is non-delimited. | ||
*/ | ||
public fun matches(other: Part): Boolean { | ||
return this.text.equals(other.text, ignoreCase = (this.regular || other.regular)) | ||
} | ||
|
||
/** | ||
* Compares the case-preserved text of two identifiers — that is case-sensitive equality. | ||
*/ | ||
override fun equals(other: Any?): Boolean { | ||
if (this === other) { | ||
return true | ||
} | ||
if (other == null || javaClass != other.javaClass) { | ||
return false | ||
} | ||
return this.text == (other as Part).text | ||
} | ||
|
||
/** | ||
* Returns the hashcode of the identifier's case-preserved text. | ||
*/ | ||
override fun hashCode(): Int { | ||
return this.text.hashCode() | ||
} | ||
|
||
/** | ||
* Return the identifier as a SQL string. | ||
*/ | ||
override fun toString(): String = when (regular) { | ||
true -> "\"${text}\"" | ||
false -> text | ||
} | ||
|
||
public companion object { | ||
|
||
@JvmStatic | ||
public fun regular(text: String): Part = Part(text, true) | ||
|
||
@JvmStatic | ||
public fun delimited(text: String): Part = Part(text, false) | ||
} | ||
} | ||
|
||
public companion object { | ||
|
||
@JvmStatic | ||
public fun regular(text: String): Identifier = Identifier(emptyArray(), Part.regular(text)) | ||
|
||
@JvmStatic | ||
public fun delimited(text: String): Identifier = Identifier(emptyArray(), Part.delimited(text)) | ||
|
||
@JvmStatic | ||
public fun of(part: Part): Identifier = Identifier(emptyArray(), part) | ||
|
||
@JvmStatic | ||
public fun of(vararg parts: Part): Identifier = TODO() | ||
|
||
@JvmStatic | ||
public fun of(parts: Collection<Part>): Identifier = TODO() | ||
|
||
@JvmStatic | ||
public fun of(vararg parts: String): Identifier { | ||
TODO() | ||
} | ||
|
||
@JvmStatic | ||
public fun of(parts: Collection<String>): Identifier { | ||
TODO() | ||
} | ||
} | ||
} |
69 changes: 60 additions & 9 deletions
69
partiql-planner/src/main/kotlin/org/partiql/planner/catalog/Name.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,79 @@ | ||
package org.partiql.planner.catalog | ||
|
||
/** | ||
* Thin wrapper over a list of strings. | ||
* A reference to a named object in a catalog; case-preserved. | ||
*/ | ||
public data class Name( | ||
public class Name( | ||
private val namespace: Namespace, | ||
private val name: String, | ||
) { | ||
|
||
/** | ||
* Returns the unqualified name part. | ||
*/ | ||
public fun getName(): String = name | ||
|
||
/** | ||
* Returns the name's namespace. | ||
*/ | ||
public fun getNamespace(): Namespace = namespace | ||
|
||
/** | ||
* Returns true if the namespace is non-empty. | ||
*/ | ||
public fun hasNamespace(): Boolean = !namespace.isEmpty() | ||
|
||
public fun getName(): String = name | ||
/** | ||
* Compares two names including their namespaces and symbols. | ||
*/ | ||
override fun equals(other: Any?): Boolean { | ||
if (this === other) { | ||
return true | ||
} | ||
if (other == null || javaClass != other.javaClass) { | ||
return false | ||
} | ||
other as Name | ||
return (this.name == other.name) && (this.namespace == other.namespace) | ||
} | ||
|
||
/** | ||
* The hashCode() is case-sensitive. | ||
*/ | ||
override fun hashCode(): Int { | ||
var result = 1 | ||
result = 31 * result + namespace.hashCode() | ||
result = 31 * result + name.hashCode() | ||
return result | ||
} | ||
|
||
/** | ||
* Return the SQL name representation of this name — all parts delimited. | ||
*/ | ||
override fun toString(): String { | ||
val parts = mutableListOf<String>() | ||
parts.addAll(namespace.getLevels()) | ||
parts.add(name) | ||
return Identifier.of(parts).toString() | ||
} | ||
|
||
public companion object { | ||
|
||
/** | ||
* Construct a name from a string. | ||
*/ | ||
@JvmStatic | ||
public fun of(vararg names: String): Name = of(names.toList()) | ||
|
||
/** | ||
* Construct a name from a collection of strings. | ||
*/ | ||
@JvmStatic | ||
public fun of(vararg names: String): Name { | ||
assert(names.size > 1) { "Cannot create an empty" } | ||
return Name( | ||
namespace = Namespace.of(*names.drop(1).toTypedArray()), | ||
name = names.last(), | ||
) | ||
public fun of(names: Collection<String>): Name { | ||
assert(names.size > 1) { "Cannot create an empty name" } | ||
val namespace = Namespace.of(names.drop(1)) | ||
val name = names.last() | ||
return Name(namespace, name) | ||
} | ||
} | ||
} |
Oops, something went wrong.