-
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.
Merges v1-metadata-catalog identifier factoring
- Loading branch information
Showing
9 changed files
with
226 additions
and
136 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
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
164 changes: 139 additions & 25 deletions
164
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 |
---|---|---|
@@ -1,69 +1,183 @@ | ||
package org.partiql.planner.catalog | ||
|
||
/** | ||
* Represents an SQL identifier (<regular identifier>) which is regular (unquoted) or delimited (double-quoted). | ||
* Represents an SQL identifier (possibly qualified). | ||
* | ||
* @property text The identifier body. | ||
* @property regular True if the identifier should be treated as an SQL regular identifier. | ||
* @property qualifier If | ||
* @property identifier | ||
*/ | ||
public class Identifier private constructor( | ||
private val text: String, | ||
private val regular: Boolean, | ||
private val qualifier: Array<Part>, | ||
private val identifier: Part, | ||
) { | ||
|
||
/** | ||
* Returns the identifier's case-preserved text. | ||
* Returns the unqualified name part. | ||
*/ | ||
public fun getText(): String = text | ||
public fun getIdentifier(): Part = identifier | ||
|
||
/** | ||
* Compares this identifier to a string. | ||
* Returns the name's namespace. | ||
*/ | ||
public fun matches(other: String): Boolean { | ||
return this.text.equals(other, ignoreCase = this.regular) | ||
} | ||
public fun getQualifier(): Array<Part> = qualifier | ||
|
||
/** | ||
* Compares two identifiers, ignoring case iff at least one identifier is non-delimited. | ||
* Returns true if the namespace is non-empty. | ||
*/ | ||
public fun matches(other: Identifier): Boolean { | ||
return this.text.equals(other.text, ignoreCase = (this.regular || other.regular)) | ||
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. | ||
*/ | ||
override fun equals(other: Any?): Boolean { | ||
public override fun equals(other: Any?): Boolean { | ||
if (this === other) { | ||
return true | ||
} | ||
if (other == null || javaClass != other.javaClass) { | ||
return false | ||
} | ||
return this.text == (other as Identifier).text | ||
other as Identifier | ||
return (this.identifier == other.identifier && this.qualifier.contentEquals(other.qualifier)) | ||
} | ||
|
||
/** | ||
* Returns the hashcode of the identifier's case-preserved text. | ||
* The hashCode() is case-sensitive — java.util.Arrays.hashCode | ||
*/ | ||
override fun hashCode(): Int { | ||
return this.text.hashCode() | ||
public override fun hashCode(): Int { | ||
var result = 1 | ||
result = 31 * result + qualifier.hashCode() | ||
result = 31 * result + identifier.hashCode() | ||
return result | ||
} | ||
|
||
/** | ||
* Return the identifier as a SQL string. | ||
* Return the SQL representation of this identifier. | ||
*/ | ||
override fun toString(): String = when (regular) { | ||
true -> "\"${text}\"" | ||
false -> text | ||
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(text, true) | ||
public fun regular(text: String): Identifier = Identifier(emptyArray(), Part.regular(text)) | ||
|
||
@JvmStatic | ||
public fun delimited(text: String): Identifier = Identifier(text, false) | ||
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 = of(parts.toList()) | ||
|
||
@JvmStatic | ||
public fun of(parts: Collection<Part>): Identifier { | ||
if (parts.isEmpty()) { | ||
error("Cannot create an identifier with no parts") | ||
} | ||
val qualifier = parts.drop(1).toTypedArray() | ||
val identifier = parts.last() | ||
return Identifier(qualifier, identifier) | ||
} | ||
|
||
@JvmStatic | ||
public fun of(vararg parts: String): Identifier = of(parts.toList()) | ||
|
||
@JvmStatic | ||
public fun of(parts: Collection<String>): Identifier { | ||
if (parts.isEmpty()) { | ||
error("Cannot create an identifier with no parts") | ||
} | ||
val qualifier = parts.drop(1).map { Part.delimited(it) }.toTypedArray() | ||
val identifier = Part.delimited(parts.last()) | ||
return Identifier(qualifier, identifier) | ||
} | ||
} | ||
} |
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
Oops, something went wrong.