LENS-531 : Add cli command to show all queryable fields of cube or dimension
Project: http://git-wip-us.apache.org/repos/asf/incubator-lens/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-lens/commit/ff31ad96 Tree: http://git-wip-us.apache.org/repos/asf/incubator-lens/tree/ff31ad96 Diff: http://git-wip-us.apache.org/repos/asf/incubator-lens/diff/ff31ad96 Branch: refs/heads/current-release-line Commit: ff31ad96b928850f4d549ebcde7e79f260b025e7 Parents: 7a7bdec Author: Rajat Khandelwal <[email protected]> Authored: Fri Jun 12 11:31:19 2015 +0530 Committer: Amareshwari Sriramadasu <[email protected]> Committed: Fri Jun 12 11:31:19 2015 +0530 ---------------------------------------------------------------------- lens-api/pom.xml | 5 + lens-api/src/main/resources/cube-0.1.xsd | 611 ++++++++++--------- .../LensCRUDStoragePartitionCommand.java | 114 ---- .../lens/cli/commands/LensCubeCommands.java | 21 +- .../cli/commands/LensDimensionCommands.java | 19 +- .../commands/LensDimensionTableCommands.java | 2 +- .../lens/cli/commands/LensFactCommands.java | 2 +- .../lens/cli/commands/LensQueryCommands.java | 3 +- .../cli/commands/LogicalTableCrudCommand.java | 31 + .../cli/commands/PhysicalTableCrudCommand.java | 114 ++++ .../org/apache/lens/cli/skel/LensBanner.java | 5 + .../lens/cli/skel/LensHistoryFileProvider.java | 2 +- .../lens/cli/skel/LensPromptProvider.java | 2 +- .../apache/lens/cli/table/CollectionTable.java | 59 ++ .../lens/cli/table/CollectionTableFactory.java | 158 +++++ .../lens/cli/table/XFlattenedColumnTable.java | 97 +++ .../apache/lens/cli/table/XJoinChainTable.java | 77 +++ .../apache/lens/cli/TestLensCubeCommands.java | 40 +- .../lens/cli/TestLensDimensionCommands.java | 26 +- .../apache/lens/cli/TestLensQueryCommands.java | 15 +- .../java/org/apache/lens/client/LensClient.java | 7 + .../apache/lens/client/LensMetadataClient.java | 35 +- .../api/metastore/CubeMetastoreService.java | 6 +- .../metastore/CubeMetastoreServiceImpl.java | 80 ++- .../server/metastore/MetastoreResource.java | 36 +- pom.xml | 7 +- src/site/apt/user/cli.apt | 10 +- 27 files changed, 1109 insertions(+), 475 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-api/pom.xml ---------------------------------------------------------------------- diff --git a/lens-api/pom.xml b/lens-api/pom.xml index adc464a..184f8a8 100644 --- a/lens-api/pom.xml +++ b/lens-api/pom.xml @@ -66,6 +66,10 @@ <groupId>com.typesafe</groupId> <artifactId>config</artifactId> </dependency> + <dependency> + <groupId>org.jvnet.jaxb2_commons</groupId> + <artifactId>jaxb2-basics-runtime</artifactId> + </dependency> </dependencies> <build> <plugins> @@ -85,6 +89,7 @@ <args> <arg>-extension</arg> <arg>-Xinheritance</arg> + <arg>-XtoString</arg> </args> <plugins> <plugin> http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-api/src/main/resources/cube-0.1.xsd ---------------------------------------------------------------------- diff --git a/lens-api/src/main/resources/cube-0.1.xsd b/lens-api/src/main/resources/cube-0.1.xsd index 719d10d..2ae606f 100644 --- a/lens-api/src/main/resources/cube-0.1.xsd +++ b/lens-api/src/main/resources/cube-0.1.xsd @@ -18,18 +18,53 @@ under the License. --> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" attributeFormDefault="unqualified" elementFormDefault="qualified" +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" + attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="uri:lens:cube:0.1" xmlns="uri:lens:cube:0.1" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.1"> + <xs:annotation> <xs:appinfo> <jaxb:schemaBindings> - <jaxb:package name="org.apache.lens.api.metastore" /> + <jaxb:package name="org.apache.lens.api.metastore"/> </jaxb:schemaBindings> </xs:appinfo> </xs:annotation> - <xs:element name="x_cube" abstract="true" type="x_cube" /> + <xs:element name="x_field" abstract="true" type="x_field"/> + + <xs:complexType name="x_field" abstract="true"> + <xs:annotation> + <xs:documentation> + some documentation + </xs:documentation> + </xs:annotation> + <xs:attribute type="xs:string" name="name" use="required"/> + <xs:attribute type="xs:string" name="display_string"> + <xs:annotation> + <xs:documentation> + Display string that should be shown to end users. Can be space separated. It gives UI systems + built on top to use this value to show the field to end user. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="xs:string" name="description"/> + </xs:complexType> + + <xs:element name="x_fields" type="x_fields"/> + + <xs:complexType name="x_fields"> + <xs:annotation> + <xs:documentation> + Set of fields. + </xs:documentation> + </xs:annotation> + <xs:sequence> + <xs:element type="x_field" name="fields" maxOccurs="unbounded" minOccurs="1"/> + </xs:sequence> + </xs:complexType> + + <xs:element name="x_cube" abstract="true" type="x_cube"/> <xs:complexType name="x_cube" abstract="true"> <xs:annotation> @@ -65,44 +100,44 @@ Additional properties: 1. cube.timedim.relation.{time_dim1}: time_dim2+[timediff1,timediff2]. It's assumed that - timediff1 is smaller than timediff2. Means that time_dim1 can be expected to be between - [time_dim2+timediff1 and time_dim2+timediff2]. One use case would be the following: + timediff1 is smaller than timediff2. Means that time_dim1 can be expected to be between + [time_dim2+timediff1 and time_dim2+timediff2]. One use case would be the following: - 1.1. if a query is on range of time_dim1 and - time_dim1 has no partitioning column in some fact, then partitions for time_dim2 can be looked at. - Let's say time_dim2's part col is part_col2, then for a query asking for time_dim1 between [a,b) can - be answered by looking at partitions of part_col2 in range [a-timediff2, b-timediff1). + 1.1. if a query is on range of time_dim1 and + time_dim1 has no partitioning column in some fact, then partitions for time_dim2 can be looked at. + Let's say time_dim2's part col is part_col2, then for a query asking for time_dim1 between [a,b) can + be answered by looking at partitions of part_col2 in range [a-timediff2, b-timediff1). - This property is first looked into fact properties, then cube properties and if that's a derived cube, - then next in base cube properties. Wherever found first, that will be considered as the final relation - between time dimensions. + This property is first looked into fact properties, then cube properties and if that's a derived cube, + then next in base cube properties. Wherever found first, that will be considered as the final relation + between time dimensions. - Time dimension relations are transitive, but not reversible. i.e. - cube.timedim.relation.time_dim1 = time_dim2 + [a, b] - cube.timedim.relation.time_dim2 = time_dim3 + [c, d] + Time dimension relations are transitive, but not reversible. i.e. + cube.timedim.relation.time_dim1 = time_dim2 + [a, b] + cube.timedim.relation.time_dim2 = time_dim3 + [c, d] - implies: + implies: - cube.timedim.relation.time_dim1 = time_dim3 + [a+c, b+d] + cube.timedim.relation.time_dim1 = time_dim3 + [a+c, b+d] - but not: + but not: - cube.timedim.relation.time_dim2 = time_dim1 + [-b, -a] + cube.timedim.relation.time_dim2 = time_dim1 + [-b, -a] - Reverse relations have to be defined explicitly. + Reverse relations have to be defined explicitly. - Timediff syntax is sign, quantity and unit. Spaces in between can be present. e.g. -4 days, +4days, +4 day - etc all are valid. + Timediff syntax is sign, quantity and unit. Spaces in between can be present. e.g. -4 days, +4days, +4 day + etc all are valid. </xs:documentation> </xs:annotation> </xs:element> </xs:sequence> - <xs:attribute type="xs:string" name="name" use="required" /> - <xs:attribute type="xs:string" name="description" /> + <xs:attribute type="xs:string" name="name" use="required"/> + <xs:attribute type="xs:string" name="description"/> </xs:complexType> - <xs:element name="x_base_cube" type="x_base_cube" /> + <xs:element name="x_base_cube" type="x_base_cube"/> <xs:complexType name="x_base_cube"> <xs:annotation> <xs:documentation> @@ -113,16 +148,16 @@ <xs:complexContent> <xs:extension base="x_cube"> <xs:sequence> - <xs:element type="x_measures" name="measures" maxOccurs="1" minOccurs="1" /> - <xs:element type="x_dim_attributes" name="dim_attributes" maxOccurs="1" minOccurs="0" /> - <xs:element type="x_expressions" name="expressions" maxOccurs="1" minOccurs="0" /> - <xs:element type="x_join_chains" name="join_chains" maxOccurs="1" minOccurs="0" /> + <xs:element type="x_measures" name="measures" maxOccurs="1" minOccurs="1"/> + <xs:element type="x_dim_attributes" name="dim_attributes" maxOccurs="1" minOccurs="0"/> + <xs:element type="x_expressions" name="expressions" maxOccurs="1" minOccurs="0"/> + <xs:element type="x_join_chains" name="join_chains" maxOccurs="1" minOccurs="0"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> - <xs:element name="x_derived_cube" type="x_derived_cube" /> + <xs:element name="x_derived_cube" type="x_derived_cube"/> <xs:complexType name="x_derived_cube"> <xs:annotation> <xs:documentation> @@ -134,10 +169,10 @@ <xs:complexContent> <xs:extension base="x_cube"> <xs:sequence> - <xs:element type="x_measure_names" name="measure_names" maxOccurs="1" minOccurs="0" /> - <xs:element type="x_dim_attr_names" name="dim_attr_names" maxOccurs="1" minOccurs="0" /> + <xs:element type="x_measure_names" name="measure_names" maxOccurs="1" minOccurs="0"/> + <xs:element type="x_dim_attr_names" name="dim_attr_names" maxOccurs="1" minOccurs="0"/> </xs:sequence> - <xs:attribute type="xs:string" name="parent" use="required" /> + <xs:attribute type="xs:string" name="parent" use="required"/> </xs:extension> </xs:complexContent> </xs:complexType> @@ -151,13 +186,13 @@ </xs:documentation> </xs:annotation> <xs:sequence> - <xs:element type="x_dim_attributes" name="attributes" maxOccurs="1" minOccurs="0" /> - <xs:element type="x_expressions" name="expressions" maxOccurs="1" minOccurs="0" /> - <xs:element type="x_join_chains" name="join_chains" maxOccurs="1" minOccurs="0" /> - <xs:element type="x_properties" name="properties" maxOccurs="1" minOccurs="0" /> + <xs:element type="x_dim_attributes" name="attributes" maxOccurs="1" minOccurs="0"/> + <xs:element type="x_expressions" name="expressions" maxOccurs="1" minOccurs="0"/> + <xs:element type="x_join_chains" name="join_chains" maxOccurs="1" minOccurs="0"/> + <xs:element type="x_properties" name="properties" maxOccurs="1" minOccurs="0"/> </xs:sequence> - <xs:attribute type="xs:string" name="name" use="required" /> - <xs:attribute type="xs:string" name="description" /> + <xs:attribute type="xs:string" name="name" use="required"/> + <xs:attribute type="xs:string" name="description"/> </xs:complexType> <xs:complexType name="x_property"> @@ -166,8 +201,8 @@ A key-value pair for storing property's name and its value. </xs:documentation> </xs:annotation> - <xs:attribute type="xs:string" name="name" use="required" /> - <xs:attribute type="xs:string" name="value" use="required" /> + <xs:attribute type="xs:string" name="name" use="required"/> + <xs:attribute type="xs:string" name="value" use="required"/> </xs:complexType> <xs:complexType name="x_properties"> @@ -187,72 +222,68 @@ A cube measure. </xs:documentation> </xs:annotation> - <xs:attribute type="xs:string" name="name" use="required" /> - <xs:attribute type="x_measure_type" name="type" use="required" /> - <xs:attribute type="xs:string" name="description" /> - <xs:attribute type="xs:string" name="display_string"> - <xs:annotation> - <xs:documentation> - Display string that should be shown to end users. Can be comma separated. It gives UI systems - built on top to use this value to show the field to end user. - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="xs:string" name="default_aggr"> - <xs:annotation> - <xs:documentation> - The aggregate for the measure that is used to rollup in aggregated facts. - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="xs:string" name="format_string"> - <xs:annotation> - <xs:documentation> - The string format that can should be used to format the number shown to user. For example: - formatting with respect to precision upto 3 decimals, can be specified as - format_number(%s,"##################.###") - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="xs:dateTime" name="start_time"> - <xs:annotation> - <xs:documentation> - The start time from when the measure is available for querying - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="xs:dateTime" name="end_time"> - <xs:annotation> - <xs:documentation> - The end time till when the measure is available for querying - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="xs:string" name="unit"> - <xs:annotation> - <xs:documentation> - Specify the unit of the measure. For example, currency in dollars or rupees. - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="xs:double" name="min"> - <xs:annotation> - <xs:documentation> - The minimum value the measure can take. This is only indicative value for user to know what - vaues it can take. Lens does not do any validation based on this value. - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="xs:double" name="max"> - <xs:annotation> - <xs:documentation> - The maximum value the measure can take. This is only indicative value for user to know what - vaues it can take. Lens does not do any validation based on this value. - </xs:documentation> - </xs:annotation> - </xs:attribute> + <xs:complexContent> + <xs:extension base="x_field"> + <xs:attribute type="x_measure_type" name="type" use="required"/> + <xs:attribute type="xs:string" name="default_aggr"> + <xs:annotation> + <xs:documentation> + The aggregate for the measure that is used to rollup in aggregated facts. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="xs:string" name="format_string"> + <xs:annotation> + <xs:documentation> + The string format that can should be used to format the number shown to user. For example: + formatting with respect to precision upto 3 decimals, can be specified as + format_number(%s,"##################.###") + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="xs:dateTime" name="start_time"> + <xs:annotation> + <xs:documentation> + The start time from when the measure is available for querying + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="xs:dateTime" name="end_time"> + <xs:annotation> + <xs:documentation> + The end time till when the measure is available for querying + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="xs:string" name="unit"> + <xs:annotation> + <xs:documentation> + Specify the unit of the measure. For example, currency in dollars or rupees. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="xs:double" name="min"> + <xs:annotation> + <xs:documentation> + The minimum value the measure can take. This is only indicative value for user to know what + vaues it can take. Lens does not do any validation based on this value. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="xs:double" name="max"> + <xs:annotation> + <xs:documentation> + The maximum value the measure can take. This is only indicative value for user to know what + vaues it can take. Lens does not do any validation based on this value. + </xs:documentation> + </xs:annotation> + </xs:attribute> + </xs:extension> + </xs:complexContent> </xs:complexType> + <xs:element name="x_measures" type="x_measures"/> + <xs:complexType name="x_measures"> <xs:annotation> <xs:documentation> @@ -281,35 +312,29 @@ An expression column </xs:documentation> </xs:annotation> - <xs:sequence> - <xs:annotation> - <xs:documentation> - All the expressions associated with expression column. - </xs:documentation> - </xs:annotation> - <xs:element type="x_expr_spec" name="expr_spec" maxOccurs="unbounded" minOccurs="1"/> - </xs:sequence> - <xs:attribute type="xs:string" name="name" use="required" /> - <xs:attribute type="xs:string" name="type" use="required"> - <xs:annotation> - <xs:documentation> - The type indicating what the evaluation of expression will produce. Allowed types are BOOLEAN, TINYINT, - SMALLINT, INT, BIGINT, FLOAT, DOUBLE, DECIMAL, STRING, CHAR, VARCHAR, DATE, TIMESTAMP, BINARY, ARRAY, MAP, - STRUCT, UNION - See hive represenation for specifying complex types - - https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Types#LanguageManualTypes-ComplexTypes - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="xs:string" name="description" /> - <xs:attribute type="xs:string" name="display_string"> - <xs:annotation> - <xs:documentation> - Display string that should be shown to end users. Can be comma separated. It gives UI systems - built on top to use this value to show the field to end user. - </xs:documentation> - </xs:annotation> - </xs:attribute> + <xs:complexContent> + <xs:extension base="x_field"> + <xs:sequence> + <xs:annotation> + <xs:documentation> + All the expressions associated with expression column. + </xs:documentation> + </xs:annotation> + <xs:element type="x_expr_spec" name="expr_spec" maxOccurs="unbounded" minOccurs="1"/> + </xs:sequence> + <xs:attribute type="xs:string" name="type" use="required"> + <xs:annotation> + <xs:documentation> + The type indicating what the evaluation of expression will produce. Allowed types are BOOLEAN, TINYINT, + SMALLINT, INT, BIGINT, FLOAT, DOUBLE, DECIMAL, STRING, CHAR, VARCHAR, DATE, TIMESTAMP, BINARY, ARRAY, MAP, + STRUCT, UNION + See hive represenation for specifying complex types - + https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Types#LanguageManualTypes-ComplexTypes + </xs:documentation> + </xs:annotation> + </xs:attribute> + </xs:extension> + </xs:complexContent> </xs:complexType> <xs:complexType name="x_expr_spec"> @@ -345,6 +370,8 @@ </xs:attribute> </xs:complexType> + <xs:element name="x_expressions" type="x_expressions"/> + <xs:complexType name="x_expressions"> <xs:annotation> <xs:documentation> @@ -362,81 +389,78 @@ A dim attribute. </xs:documentation> </xs:annotation> - <xs:sequence> - <xs:element name="ref_spec" maxOccurs="1" minOccurs="0"> - <xs:annotation> - <xs:documentation> - Reference specifiction needs to be specified if the attribute is a reference attribute. It - can either be table reference or a chained column - - ref_spec can be specified as a list of table references to - which the attribute is refering to. - For ex : userid refers user.id, xuser.id, yuser.id, zuser.id. - - Alternately, ref_spec could be a chained column specifed with chain name and column name. - </xs:documentation> - </xs:annotation> - <xs:complexType> - <xs:choice maxOccurs="1" minOccurs="1"> - <xs:element type="x_table_references" name="table_references" maxOccurs="1" minOccurs="1" /> - <xs:element type="x_chain_column" name="chain_ref_column" maxOccurs="1" minOccurs="1" /> - </xs:choice> - </xs:complexType> - </xs:element> - </xs:sequence> - <xs:attribute type="xs:string" name="name" use="required" /> - <xs:attribute type="xs:string" name="type" use="required"> - <xs:annotation> - <xs:documentation> - The type indicating what the evaluation of expression will produce. Allowed types are BOOLEAN,TINYINT, - SMALLINT, INT, BIGINT, FLOAT, DOUBLE, DECIMAL, STRING, CHAR, VARCHAR, DATE, TIMESTAMP, BINARY, ARRAY, MAP, - STRUCT, UNION - See hive represenation for specifying complex types - - https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Types#LanguageManualTypes-ComplexTypes - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="xs:string" name="description" /> - <xs:attribute type="xs:string" name="display_string"> - <xs:annotation> - <xs:documentation> - Display string that should be shown to end users. Can be comma separated. It gives UI systems - built on top to use this value to show the field to end user. - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="xs:dateTime" name="start_time"> - <xs:annotation> - <xs:documentation> - The start time from when the attribute is available for querying. - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="xs:dateTime" name="end_time"> - <xs:annotation> - <xs:documentation> - The end time till when the attribute is available for querying. - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="xs:long" name="num_distinct_values" use="optional"> - <xs:annotation> - <xs:documentation> - Specifies an indicative value of how many distinct values the dim attribute can take. - This would give an idea of how big the grouping will be when an attribute is chosen for groupby expressions. - This is just an approximate value. - </xs:documentation> - </xs:annotation> - </xs:attribute> - <xs:attribute type="xs:boolean" name="join_key" default="false"> - <xs:annotation> - <xs:documentation> - This flag will tell whether the attribute can be used as a join key or not - </xs:documentation> - </xs:annotation> - </xs:attribute> + <xs:complexContent> + <xs:extension base="x_field"> + <xs:sequence> + <xs:element name="ref_spec" maxOccurs="1" minOccurs="0"> + <xs:annotation> + <xs:documentation> + Reference specifiction needs to be specified if the attribute is a reference attribute. It + can either be table reference or a chained column + + ref_spec can be specified as a list of table references to + which the attribute is refering to. + For ex : userid refers user.id, xuser.id, yuser.id, zuser.id. + + Alternately, ref_spec could be a chained column specifed with chain name and column name. + </xs:documentation> + </xs:annotation> + <xs:complexType> + <xs:choice maxOccurs="1" minOccurs="1"> + <xs:element type="x_table_references" name="table_references" maxOccurs="1" minOccurs="1"/> + <xs:element type="x_chain_column" name="chain_ref_column" maxOccurs="1" minOccurs="1"/> + </xs:choice> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute type="xs:string" name="type" use="required"> + <xs:annotation> + <xs:documentation> + The type indicating what the evaluation of expression will produce. Allowed types are BOOLEAN,TINYINT, + SMALLINT, INT, BIGINT, FLOAT, DOUBLE, DECIMAL, STRING, CHAR, VARCHAR, DATE, TIMESTAMP, BINARY, ARRAY, MAP, + STRUCT, UNION + See hive represenation for specifying complex types - + https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Types#LanguageManualTypes-ComplexTypes + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="xs:dateTime" name="start_time"> + <xs:annotation> + <xs:documentation> + The start time from when the attribute is available for querying. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="xs:dateTime" name="end_time"> + <xs:annotation> + <xs:documentation> + The end time till when the attribute is available for querying. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="xs:long" name="num_distinct_values" use="optional"> + <xs:annotation> + <xs:documentation> + Specifies an indicative value of how many distinct values the dim attribute can take. + This would give an idea of how big the grouping will be when an attribute is chosen for groupby + expressions. + This is just an approximate value. + </xs:documentation> + </xs:annotation> + </xs:attribute> + <xs:attribute type="xs:boolean" name="join_key" default="false"> + <xs:annotation> + <xs:documentation> + This flag will tell whether the attribute can be used as a join key or not + </xs:documentation> + </xs:annotation> + </xs:attribute> + </xs:extension> + </xs:complexContent> </xs:complexType> + <xs:element name="x_dim_attributes" type="x_dim_attributes"/> + <xs:complexType name="x_dim_attributes"> <xs:annotation> <xs:documentation> @@ -460,8 +484,8 @@ </xs:complexType> <xs:complexType name="x_chain_column"> - <xs:attribute type="xs:string" name="chain_name" use="required" /> - <xs:attribute type="xs:string" name="ref_col" use="required" /> + <xs:attribute type="xs:string" name="chain_name" use="required"/> + <xs:attribute type="xs:string" name="ref_col" use="required"/> <xs:attribute type="xs:string" name="dest_table"> <xs:annotation> <xs:documentation> @@ -472,8 +496,8 @@ </xs:complexType> <xs:complexType name="x_table_reference"> - <xs:attribute type="xs:string" name="table" use="required" /> - <xs:attribute type="xs:string" name="column" use="required" /> + <xs:attribute type="xs:string" name="table" use="required"/> + <xs:attribute type="xs:string" name="column" use="required"/> </xs:complexType> <xs:complexType name="x_table_references"> @@ -487,6 +511,8 @@ </xs:sequence> </xs:complexType> + <xs:element name="x_join_chains" type="x_join_chains"/> + <xs:complexType name="x_join_chains"> <xs:annotation> <xs:documentation> @@ -513,19 +539,20 @@ SalesCube.productionStateid -> State.id, State.countryid ->Country.id will be named differently. </xs:documentation> </xs:annotation> - <xs:sequence> - <xs:element type="x_join_paths" name="paths" maxOccurs="1" minOccurs="1" /> - </xs:sequence> - <xs:attribute type="xs:string" name="name" use="required" /> - <xs:attribute type="xs:string" name="description" /> - <xs:attribute type="xs:string" name="display_string" /> - <xs:attribute type="xs:string" name="dest_table"> - <xs:annotation> - <xs:documentation> - This will be the destination table of the chain. LENS will set and return, need not be set by end-user. - </xs:documentation> - </xs:annotation> - </xs:attribute> + <xs:complexContent> + <xs:extension base="x_field"> + <xs:sequence> + <xs:element type="x_join_paths" name="paths" maxOccurs="1" minOccurs="1"/> + </xs:sequence> + <xs:attribute type="xs:string" name="dest_table"> + <xs:annotation> + <xs:documentation> + This will be the destination table of the chain. LENS will set and return, need not be set by end-user. + </xs:documentation> + </xs:annotation> + </xs:attribute> + </xs:extension> + </xs:complexContent> </xs:complexType> <xs:complexType name="x_join_path"> @@ -535,7 +562,7 @@ </xs:documentation> </xs:annotation> <xs:sequence> - <xs:element type="x_join_edges" name="edges" maxOccurs="1" minOccurs="1" /> + <xs:element type="x_join_edges" name="edges" maxOccurs="1" minOccurs="1"/> </xs:sequence> </xs:complexType> @@ -557,8 +584,8 @@ </xs:documentation> </xs:annotation> <xs:sequence> - <xs:element type="x_table_reference" name="from" maxOccurs="1" minOccurs="1" /> - <xs:element type="x_table_reference" name="to" maxOccurs="1" minOccurs="1" /> + <xs:element type="x_table_reference" name="from" maxOccurs="1" minOccurs="1"/> + <xs:element type="x_table_reference" name="to" maxOccurs="1" minOccurs="1"/> </xs:sequence> </xs:complexType> @@ -596,10 +623,10 @@ <xs:annotation> <xs:documentation> Dimension table properties. The properties that should be set are: - 1. dimtable.{dim_table_name}.part.cols = comma separated list of partition columns of this dimtable. - This would basically be union of all partition columns of all storage tables of the dimtable. - Setting this makes that partition column queryable. - Time part columns can be skipped as they will generally not be queried. + 1. dimtable.{dim_table_name}.part.cols = comma separated list of partition columns of this dimtable. + This would basically be union of all partition columns of all storage tables of the dimtable. + Setting this makes that partition column queryable. + Time part columns can be skipped as they will generally not be queried. </xs:documentation> </xs:annotation> </xs:element> @@ -659,7 +686,7 @@ Column in table. </xs:documentation> </xs:annotation> - <xs:attribute name="name" type="xs:string" use="required" /> + <xs:attribute name="name" type="xs:string" use="required"/> <xs:attribute type="xs:string" name="type" use="required"> <xs:annotation> <xs:documentation> @@ -670,8 +697,8 @@ https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Types#LanguageManualTypes-ComplexTypes </xs:documentation> </xs:annotation> - </xs:attribute> - <xs:attribute name="comment" type="xs:string" /> + </xs:attribute> + <xs:attribute name="comment" type="xs:string"/> </xs:complexType> <xs:simpleType name="x_measure_type"> @@ -681,13 +708,13 @@ </xs:documentation> </xs:annotation> <xs:restriction base="xs:string"> - <xs:enumeration value="TINYINT" /> - <xs:enumeration value="SMALLINT" /> - <xs:enumeration value="INT" /> - <xs:enumeration value="BIGINT" /> - <xs:enumeration value="FLOAT" /> - <xs:enumeration value="DOUBLE" /> - <xs:enumeration value="DECIMAL" /> + <xs:enumeration value="TINYINT"/> + <xs:enumeration value="SMALLINT"/> + <xs:enumeration value="INT"/> + <xs:enumeration value="BIGINT"/> + <xs:enumeration value="FLOAT"/> + <xs:enumeration value="DOUBLE"/> + <xs:enumeration value="DECIMAL"/> </xs:restriction> </xs:simpleType> @@ -698,18 +725,18 @@ </xs:documentation> </xs:annotation> <xs:restriction base="xs:string"> - <xs:enumeration value="SECONDLY" /> - <xs:enumeration value="MINUTELY" /> - <xs:enumeration value="HOURLY" /> - <xs:enumeration value="DAILY" /> - <xs:enumeration value="WEEKLY" /> - <xs:enumeration value="MONTHLY" /> - <xs:enumeration value="QUARTERLY" /> - <xs:enumeration value="YEARLY" /> + <xs:enumeration value="SECONDLY"/> + <xs:enumeration value="MINUTELY"/> + <xs:enumeration value="HOURLY"/> + <xs:enumeration value="DAILY"/> + <xs:enumeration value="WEEKLY"/> + <xs:enumeration value="MONTHLY"/> + <xs:enumeration value="QUARTERLY"/> + <xs:enumeration value="YEARLY"/> </xs:restriction> </xs:simpleType> - <xs:element name="x_storage" type="x_storage" /> + <xs:element name="x_storage" type="x_storage"/> <xs:complexType name="x_storage"> <xs:annotation> <xs:documentation> @@ -725,7 +752,7 @@ </xs:annotation> </xs:element> </xs:sequence> - <xs:attribute name="name" type="xs:string" use="required" /> + <xs:attribute name="name" type="xs:string" use="required"/> <xs:attribute name="classname" type="xs:string" use="required"> <xs:annotation> <xs:documentation> @@ -738,7 +765,7 @@ </xs:attribute> </xs:complexType> - <xs:element name="x_storage_table_desc" type="x_storage_table_desc" /> + <xs:element name="x_storage_table_desc" type="x_storage_table_desc"/> <xs:complexType name="x_storage_table_desc"> <xs:annotation> <xs:documentation> @@ -907,9 +934,9 @@ </xs:documentation> </xs:annotation> <xs:sequence> - <xs:element name="col_names" type="xs:string" maxOccurs="unbounded" minOccurs="0" /> - <xs:element name="col_values" type="x_skew_col_list" maxOccurs="unbounded" minOccurs="0" /> - <xs:element name="value_location_map" type="x_skewed_value_location" maxOccurs="unbounded" minOccurs="0" /> + <xs:element name="col_names" type="xs:string" maxOccurs="unbounded" minOccurs="0"/> + <xs:element name="col_values" type="x_skew_col_list" maxOccurs="unbounded" minOccurs="0"/> + <xs:element name="value_location_map" type="x_skewed_value_location" maxOccurs="unbounded" minOccurs="0"/> </xs:sequence> </xs:complexType> @@ -920,7 +947,7 @@ </xs:documentation> </xs:annotation> <xs:sequence> - <xs:element name="elements" type="xs:string" maxOccurs="unbounded" minOccurs="0" /> + <xs:element name="elements" type="xs:string" maxOccurs="unbounded" minOccurs="0"/> </xs:sequence> </xs:complexType> @@ -931,12 +958,12 @@ </xs:documentation> </xs:annotation> <xs:sequence> - <xs:element name="value" type="x_skew_col_list" minOccurs="1" maxOccurs="1" /> + <xs:element name="value" type="x_skew_col_list" minOccurs="1" maxOccurs="1"/> </xs:sequence> - <xs:attribute type="xs:string" name="location" use="required" /> + <xs:attribute type="xs:string" name="location" use="required"/> </xs:complexType> - <xs:element name="x_storage_table_element" type="x_storage_table_element" /> + <xs:element name="x_storage_table_element" type="x_storage_table_element"/> <xs:complexType name="x_storage_table_element"> <xs:annotation> @@ -945,9 +972,9 @@ </xs:documentation> </xs:annotation> <xs:sequence> - <xs:element name="update_periods" type="x_update_periods" maxOccurs="1" minOccurs="0" /> - <xs:element name="storage_name" type="xs:string" /> - <xs:element type="x_storage_table_desc" name="table_desc" /> + <xs:element name="update_periods" type="x_update_periods" maxOccurs="1" minOccurs="0"/> + <xs:element name="storage_name" type="xs:string"/> + <xs:element type="x_storage_table_desc" name="table_desc"/> </xs:sequence> </xs:complexType> @@ -958,11 +985,11 @@ </xs:documentation> </xs:annotation> <xs:sequence> - <xs:element name="storage_table" minOccurs="1" maxOccurs="unbounded" type="x_storage_table_element" /> + <xs:element name="storage_table" minOccurs="1" maxOccurs="unbounded" type="x_storage_table_element"/> </xs:sequence> </xs:complexType> - <xs:element name="x_partition_list" type="x_partition_list" /> + <xs:element name="x_partition_list" type="x_partition_list"/> <xs:complexType name="x_partition_list"> <xs:annotation> <xs:documentation> @@ -970,11 +997,11 @@ </xs:documentation> </xs:annotation> <xs:sequence> - <xs:element name="partition" type="x_partition" maxOccurs="unbounded" minOccurs="0" /> + <xs:element name="partition" type="x_partition" maxOccurs="unbounded" minOccurs="0"/> </xs:sequence> </xs:complexType> - <xs:element name="x_partition" type="x_partition" /> + <xs:element name="x_partition" type="x_partition"/> <xs:complexType name="x_partition"> <xs:annotation> @@ -983,21 +1010,21 @@ </xs:documentation> </xs:annotation> <xs:sequence> - <xs:element name="non_time_partition_spec" maxOccurs="1" minOccurs="0" type ="x_part_spec" > + <xs:element name="non_time_partition_spec" maxOccurs="1" minOccurs="0" type="x_part_spec"> <xs:annotation> <xs:documentation> Non time partition specification with partition columns and values. </xs:documentation> </xs:annotation> </xs:element> - <xs:element name="time_partition_spec" maxOccurs="1" minOccurs="0" type = "x_time_part_spec" > + <xs:element name="time_partition_spec" maxOccurs="1" minOccurs="0" type="x_time_part_spec"> <xs:annotation> <xs:documentation> Time partition specification with partition columns and date values. </xs:documentation> </xs:annotation> </xs:element> - <xs:element name="full_partition_spec" maxOccurs="1" minOccurs="0" type ="x_part_spec" > + <xs:element name="full_partition_spec" maxOccurs="1" minOccurs="0" type="x_part_spec"> <xs:annotation> <xs:documentation> LENS would use this type to retun the specification elements. Should not be used directly by end-user. @@ -1078,8 +1105,8 @@ Partition column name and its value. </xs:documentation> </xs:annotation> - <xs:attribute type="xs:string" name="key" use="required" /> - <xs:attribute type="xs:string" name="value" use="required" /> + <xs:attribute type="xs:string" name="key" use="required"/> + <xs:attribute type="xs:string" name="value" use="required"/> </xs:complexType> <xs:complexType name="x_part_spec"> @@ -1094,8 +1121,8 @@ Time partition column name and its value as date-time. </xs:documentation> </xs:annotation> - <xs:attribute type="xs:string" name="key" use="required" /> - <xs:attribute type="xs:dateTime" name="value" use="required" /> + <xs:attribute type="xs:string" name="key" use="required"/> + <xs:attribute type="xs:dateTime" name="value" use="required"/> </xs:complexType> <xs:complexType name="x_time_part_spec"> @@ -1104,7 +1131,7 @@ </xs:sequence> </xs:complexType> - <xs:element name="x_fact_table" type="x_fact_table" /> + <xs:element name="x_fact_table" type="x_fact_table"/> <xs:complexType name="x_fact_table"> <xs:annotation> @@ -1127,26 +1154,26 @@ Properties that can be set for a fact are 1. cube.fact.{fact-name}.valid.columns.size : This should be set to number of - cube.fact.{fact-name}.valid.columns strings. + cube.fact.{fact-name}.valid.columns strings. 2. cube.fact.{fact-name}.valid.columns{i} : This should be set to comma separated column names which are - valid in the fact, such that 0 <= i < cube.fact.{fact-name}.valid.columns.size and each of - cube.fact.{fact-name}.valid.columns{i} has maximum length of 3999. + valid in the fact, such that 0 <= i < cube.fact.{fact-name}.valid.columns.size and each of + cube.fact.{fact-name}.valid.columns{i} has maximum length of 3999. 3. cube.fact.is.aggregated : Defaults to true. If the fact is a raw fact, this should be set to false, - otherwise true. + otherwise true. 4. cube.timedim.relation.{time_dim1}: See the same property in cube. Fact tables can override the property. 5. cube.fact.absolute.start.time: start time of the fact. For queries that ask for time before this, - this fact is not a candidate. Time format can be as you would specify in the time_range_in clause. - i.e. yyyy[-mm[-dd[-hh[:MM[:ss[,SSS]]]]]] + this fact is not a candidate. Time format can be as you would specify in the time_range_in clause. + i.e. yyyy[-mm[-dd[-hh[:MM[:ss[,SSS]]]]]] 6. cube.fact.relative.start.time: Here you can specify fact's relative validity relative to current time. - Useful if you want to specify e.g. this fact is valid for today - 90 days. Can be specified as just - a time difference e.g. "-90 days". Or can be specified in relative syntax. - e.g. now.year or now.day - 6 hour etc. + Useful if you want to specify e.g. this fact is valid for today - 90 days. Can be specified as just + a time difference e.g. "-90 days". Or can be specified in relative syntax. + e.g. now.year or now.day - 6 hour etc. 7. cube.fact.absolute.end.time: If you're deprecating this fact, put the final date till which the data of - the fact will be valid here. Format same as absolute start time. + the fact will be valid here. Format same as absolute start time. </xs:documentation> </xs:annotation> </xs:element> - <xs:element name="storage_tables" type = "x_storage_tables" maxOccurs="1" minOccurs="0"/> + <xs:element name="storage_tables" type="x_storage_tables" maxOccurs="1" minOccurs="0"/> </xs:sequence> <xs:attribute name="name" type="xs:string" use="required"> <xs:annotation> @@ -1177,7 +1204,7 @@ </xs:attribute> </xs:complexType> - <xs:element name="x_native_table" type="x_native_table" /> + <xs:element name="x_native_table" type="x_native_table"/> <xs:complexType name="x_native_table"> <xs:annotation> <xs:documentation> @@ -1246,7 +1273,7 @@ </xs:attribute> </xs:complexType> - <xs:element name="x_flattened_columns" type="x_flattened_columns" /> + <xs:element name="x_flattened_columns" type="x_flattened_columns"/> <xs:complexType name="x_flattened_columns"> <xs:annotation> <xs:documentation> @@ -1255,16 +1282,16 @@ </xs:documentation> </xs:annotation> <xs:sequence> - <xs:element name="flattened_column" type="x_flattened_column" maxOccurs="unbounded" minOccurs="0" /> + <xs:element name="flattened_column" type="x_flattened_column" maxOccurs="unbounded" minOccurs="0"/> </xs:sequence> </xs:complexType> <xs:complexType name="x_flattened_column"> <xs:choice maxOccurs="1" minOccurs="1"> - <xs:element name="measure" type="x_measure" /> - <xs:element name="expression" type="x_expr_column" /> - <xs:element name="dim_attribute" type="x_dim_attribute" /> + <xs:element name="measure" type="x_measure"/> + <xs:element name="expression" type="x_expr_column"/> + <xs:element name="dim_attribute" type="x_dim_attribute"/> </xs:choice> - <xs:attribute name="table_name" type="xs:string" use="required" /> + <xs:attribute name="table_name" type="xs:string" use="required"/> <xs:attribute name="chain_name" type="xs:string"> <xs:annotation> <xs:documentation> http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/commands/LensCRUDStoragePartitionCommand.java ---------------------------------------------------------------------- diff --git a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensCRUDStoragePartitionCommand.java b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensCRUDStoragePartitionCommand.java deleted file mode 100644 index 208081d..0000000 --- a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensCRUDStoragePartitionCommand.java +++ /dev/null @@ -1,114 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.lens.cli.commands; - -import java.io.IOException; -import java.util.List; - -import org.apache.lens.api.APIResult; -import org.apache.lens.api.metastore.XPartition; -import org.apache.lens.api.metastore.XStorageTableElement; - -import com.google.common.base.Joiner; - -public abstract class LensCRUDStoragePartitionCommand<T> extends LensCRUDCommand<T> { - public String showAll(String filter) { - List<String> all = getAll(filter); - if (all == null || all.isEmpty()) { - return "No " + getSingleObjectName() + " found" + (filter == null ? "" : " for " + filter); - } - return Joiner.on("\n").join(all); - } - - public String showAllStorages(String tableName) { - String sep = ""; - StringBuilder sb = new StringBuilder(); - List<String> storages = getAllStorages(tableName); - if (storages != null) { - for (String storage : storages) { - if (!storage.isEmpty()) { - sb.append(sep).append(storage); - sep = "\n"; - } - } - } - String ret = sb.toString(); - return ret.isEmpty() ? "No storage found for " + tableName : ret; - } - - public String addStorage(String tableName, String path) { - return doAddStorage(tableName, getValidPath(path, false, true)).toString().toLowerCase(); - } - - public String getStorage(String tableName, String storage) { - try { - return formatJson(mapper.writer(pp).writeValueAsString(readStorage(tableName, storage))); - } catch (IOException e) { - throw new IllegalArgumentException(e); - } - } - - public String dropStorage(String tableName, String storageName) { - return doDropStorage(tableName, storageName).toString().toLowerCase(); - } - - public String dropAllStorages(String tableName) { - return doDropAllStorages(tableName).toString(); - } - - public String getAllPartitions(String tableName, String storageName, String filter) { - try { - return formatJson(mapper.writer(pp).writeValueAsString(readAllPartitions(tableName, storageName, filter))); - } catch (IOException e) { - throw new IllegalArgumentException(e); - } - } - - public String addPartition(String tableName, String storageName, String path) { - return doAddPartition(tableName, storageName, getValidPath(path, false, true)).toString().toLowerCase(); - } - - public String addPartitions(String tableName, String storageName, String path) { - return doAddPartitions(tableName, storageName, getValidPath(path, false, true)).toString().toLowerCase(); - } - - public String dropPartitions(String tableName, String storageName, String filter) { - return doDropPartitions(tableName, storageName, filter).toString().toLowerCase(); - } - - protected abstract List<String> getAll(String filter); - - public abstract List<String> getAllStorages(String name); - - public abstract APIResult doAddStorage(String name, String path); - - protected abstract XStorageTableElement readStorage(String tableName, String storage); - - public abstract APIResult doDropStorage(String tableName, String storageName); - - public abstract APIResult doDropAllStorages(String name); - - protected abstract List<XPartition> readAllPartitions(String tableName, String storageName, String filter); - - protected abstract APIResult doAddPartition(String tableName, String storageName, String path); - - protected abstract APIResult doAddPartitions(String tableName, String storageName, String path); - - protected abstract APIResult doDropPartitions(String tableName, String storageName, String filter); -} http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/commands/LensCubeCommands.java ---------------------------------------------------------------------- diff --git a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensCubeCommands.java b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensCubeCommands.java index d05d7a5..6ba702f 100644 --- a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensCubeCommands.java +++ b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensCubeCommands.java @@ -35,7 +35,7 @@ import org.springframework.stereotype.Component; @Component @UserDocumentation(title = "OLAP Data cube metadata management", description = "These commands provide CRUD for cubes") -public class LensCubeCommands extends LensCRUDCommand<XCube> { +public class LensCubeCommands extends LogicalTableCrudCommand<XCube> { /** * Show cubes. @@ -106,12 +106,29 @@ public class LensCubeCommands extends LensCRUDCommand<XCube> { help = "get latest date of data available in cube <cube_name> for time dimension <time_dimension_name>. " + " Instead of time dimension, partition column can be directly passed as <time_dimension>") public String getLatest( - @CliOption(key = {"", "cube"}, mandatory = true, help = "<cube_name>") String cube, + @CliOption(key = {"", "name"}, mandatory = true, help = "<cube_name>") String cube, @CliOption(key = {"", "time_dimension"}, mandatory = true, help = "<time_dimension>") String timeDim) { Date dt = getClient().getLatestDateOfCube(cube, timeDim); return dt == null ? "No Data Available" : formatDate(dt); } + @CliCommand(value = "cube show fields", + help = "Show queryable fields of the given cube <cube_name>. " + + "Optionally specify <flattened> to include chained fields") + public String showQueryableFields( + @CliOption(key = {"", "name"}, mandatory = true, help = "<cube_name>") String table, + @CliOption(key = {"flattened"}, mandatory = false, unspecifiedDefaultValue = "false", + specifiedDefaultValue = "true", help = "<flattened>") boolean flattened) { + return getAllFields(table, flattened); + } + + @CliCommand(value = "cube show joinchains", + help = "Show joinchains of the given cube <cube_name>. ") + public String showJoinChains( + @CliOption(key = {"", "name"}, mandatory = true, help = "<cube_name>") String table) { + return getAllJoinChains(table); + } + @Override public List<String> getAll() { return getClient().getAllCubes(); http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDimensionCommands.java ---------------------------------------------------------------------- diff --git a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDimensionCommands.java b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDimensionCommands.java index 84ae6c3..de022c1 100644 --- a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDimensionCommands.java +++ b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDimensionCommands.java @@ -34,7 +34,7 @@ import org.springframework.stereotype.Component; */ @Component @UserDocumentation(title = "Dimension Management", description = "These commands provide CRUD for Dimensions") -public class LensDimensionCommands extends LensCRUDCommand<XDimension> { +public class LensDimensionCommands extends LogicalTableCrudCommand<XDimension> { /** * Show dimensions. @@ -103,6 +103,23 @@ public class LensDimensionCommands extends LensCRUDCommand<XDimension> { return drop(name, false); } + @CliCommand(value = "dimension show fields", + help = "Show queryable fields of the given dimension <dimension_name>. " + + "Optionally specify <flattened> to include chained fields") + public String showQueryableFields( + @CliOption(key = {"", "name"}, mandatory = true, help = "<dimension_name>") String table, + @CliOption(key = {"flattened"}, mandatory = false, unspecifiedDefaultValue = "false", + specifiedDefaultValue = "true", help = "<flattened>") boolean flattened) { + return getAllFields(table, flattened); + } + + @CliCommand(value = "dimension show joinchains", + help = "Show joinchains of the given dimension <dimension_name>. ") + public String showJoinChains( + @CliOption(key = {"", "name"}, mandatory = true, help = "<dimension_name>") String table) { + return getAllJoinChains(table); + } + @Override public List<String> getAll() { return getClient().getAllDimensions(); http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDimensionTableCommands.java ---------------------------------------------------------------------- diff --git a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDimensionTableCommands.java b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDimensionTableCommands.java index 40380b7..6a93393 100644 --- a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDimensionTableCommands.java +++ b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensDimensionTableCommands.java @@ -37,7 +37,7 @@ import org.springframework.stereotype.Component; @Component @UserDocumentation(title = "Commands for Dimension Tables", description = "These commands provide CRUD for dimension tables, associated storages, and fact partitions") -public class LensDimensionTableCommands extends LensCRUDStoragePartitionCommand<XDimensionTable> +public class LensDimensionTableCommands extends PhysicalTableCrudCommand<XDimensionTable> implements CommandMarker { /** http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/commands/LensFactCommands.java ---------------------------------------------------------------------- diff --git a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensFactCommands.java b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensFactCommands.java index 24992b9..bdb9c38 100644 --- a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensFactCommands.java +++ b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensFactCommands.java @@ -36,7 +36,7 @@ import org.springframework.stereotype.Component; @Component @UserDocumentation(title = "Management of Facts", description = "These command provide CRUD for facts, associated storages, and fact partitions") -public class LensFactCommands extends LensCRUDStoragePartitionCommand<XFactTable> { +public class LensFactCommands extends PhysicalTableCrudCommand<XFactTable> { /** * Show facts. http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/commands/LensQueryCommands.java ---------------------------------------------------------------------- diff --git a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensQueryCommands.java b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensQueryCommands.java index 1eb7ed6..928531e 100644 --- a/lens-cli/src/main/java/org/apache/lens/cli/commands/LensQueryCommands.java +++ b/lens-cli/src/main/java/org/apache/lens/cli/commands/LensQueryCommands.java @@ -271,7 +271,7 @@ public class LensQueryCommands extends BaseLensCommand { @CliOption(key = {"", "query_handle"}, mandatory = true, help = "<query_handle>") String qh, @CliOption(key = {"save_location"}, mandatory = false, help = "<save_location>") String location, @CliOption(key = {"async"}, mandatory = false, unspecifiedDefaultValue = "true", - help = "<async>") boolean async) { + help = "<async>") boolean async) { QueryHandle queryHandle = new QueryHandle(UUID.fromString(qh)); LensClient.LensClientResultSetWithStats results; try { @@ -459,5 +459,4 @@ public class LensQueryCommands extends BaseLensCommand { planStr.append("\n").append("Prepare handle:").append(plan.getPrepareHandle()); return planStr.toString(); } - } http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/commands/LogicalTableCrudCommand.java ---------------------------------------------------------------------- diff --git a/lens-cli/src/main/java/org/apache/lens/cli/commands/LogicalTableCrudCommand.java b/lens-cli/src/main/java/org/apache/lens/cli/commands/LogicalTableCrudCommand.java new file mode 100644 index 0000000..3c78e43 --- /dev/null +++ b/lens-cli/src/main/java/org/apache/lens/cli/commands/LogicalTableCrudCommand.java @@ -0,0 +1,31 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.lens.cli.commands; + +import org.apache.lens.cli.table.XFlattenedColumnTable; +import org.apache.lens.cli.table.XJoinChainTable; + +public abstract class LogicalTableCrudCommand<T> extends LensCRUDCommand<T> { + public String getAllFields(String table, boolean flattened) { + return new XFlattenedColumnTable(getClient().getQueryableFields(table, flattened), table).toString(); + } + public String getAllJoinChains(String table) { + return new XJoinChainTable(getClient().getJoinChains(table)).toString(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/commands/PhysicalTableCrudCommand.java ---------------------------------------------------------------------- diff --git a/lens-cli/src/main/java/org/apache/lens/cli/commands/PhysicalTableCrudCommand.java b/lens-cli/src/main/java/org/apache/lens/cli/commands/PhysicalTableCrudCommand.java new file mode 100644 index 0000000..a479c14 --- /dev/null +++ b/lens-cli/src/main/java/org/apache/lens/cli/commands/PhysicalTableCrudCommand.java @@ -0,0 +1,114 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.lens.cli.commands; + +import java.io.IOException; +import java.util.List; + +import org.apache.lens.api.APIResult; +import org.apache.lens.api.metastore.XPartition; +import org.apache.lens.api.metastore.XStorageTableElement; + +import com.google.common.base.Joiner; + +public abstract class PhysicalTableCrudCommand<T> extends LensCRUDCommand<T> { + public String showAll(String filter) { + List<String> all = getAll(filter); + if (all == null || all.isEmpty()) { + return "No " + getSingleObjectName() + " found" + (filter == null ? "" : " for " + filter); + } + return Joiner.on("\n").join(all); + } + + public String showAllStorages(String tableName) { + String sep = ""; + StringBuilder sb = new StringBuilder(); + List<String> storages = getAllStorages(tableName); + if (storages != null) { + for (String storage : storages) { + if (!storage.isEmpty()) { + sb.append(sep).append(storage); + sep = "\n"; + } + } + } + String ret = sb.toString(); + return ret.isEmpty() ? "No storage found for " + tableName : ret; + } + + public String addStorage(String tableName, String path) { + return doAddStorage(tableName, getValidPath(path, false, true)).toString().toLowerCase(); + } + + public String getStorage(String tableName, String storage) { + try { + return formatJson(mapper.writer(pp).writeValueAsString(readStorage(tableName, storage))); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } + + public String dropStorage(String tableName, String storageName) { + return doDropStorage(tableName, storageName).toString().toLowerCase(); + } + + public String dropAllStorages(String tableName) { + return doDropAllStorages(tableName).toString(); + } + + public String getAllPartitions(String tableName, String storageName, String filter) { + try { + return formatJson(mapper.writer(pp).writeValueAsString(readAllPartitions(tableName, storageName, filter))); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } + + public String addPartition(String tableName, String storageName, String path) { + return doAddPartition(tableName, storageName, getValidPath(path, false, true)).toString().toLowerCase(); + } + + public String addPartitions(String tableName, String storageName, String path) { + return doAddPartitions(tableName, storageName, getValidPath(path, false, true)).toString().toLowerCase(); + } + + public String dropPartitions(String tableName, String storageName, String filter) { + return doDropPartitions(tableName, storageName, filter).toString().toLowerCase(); + } + + protected abstract List<String> getAll(String filter); + + public abstract List<String> getAllStorages(String name); + + public abstract APIResult doAddStorage(String name, String path); + + protected abstract XStorageTableElement readStorage(String tableName, String storage); + + public abstract APIResult doDropStorage(String tableName, String storageName); + + public abstract APIResult doDropAllStorages(String name); + + protected abstract List<XPartition> readAllPartitions(String tableName, String storageName, String filter); + + protected abstract APIResult doAddPartition(String tableName, String storageName, String path); + + protected abstract APIResult doAddPartitions(String tableName, String storageName, String path); + + protected abstract APIResult doDropPartitions(String tableName, String storageName, String filter); +} http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/skel/LensBanner.java ---------------------------------------------------------------------- diff --git a/lens-cli/src/main/java/org/apache/lens/cli/skel/LensBanner.java b/lens-cli/src/main/java/org/apache/lens/cli/skel/LensBanner.java index 86099d3..f577509 100644 --- a/lens-cli/src/main/java/org/apache/lens/cli/skel/LensBanner.java +++ b/lens-cli/src/main/java/org/apache/lens/cli/skel/LensBanner.java @@ -47,4 +47,9 @@ public class LensBanner extends DefaultBannerProvider { public String getWelcomeMessage() { return "Welcome to Lens Client"; } + + @Override + public String getVersion() { + return getClass().getPackage().getImplementationVersion() + " built with spring shell " + super.getVersion(); + } } http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/skel/LensHistoryFileProvider.java ---------------------------------------------------------------------- diff --git a/lens-cli/src/main/java/org/apache/lens/cli/skel/LensHistoryFileProvider.java b/lens-cli/src/main/java/org/apache/lens/cli/skel/LensHistoryFileProvider.java index b599d6e..905a019 100644 --- a/lens-cli/src/main/java/org/apache/lens/cli/skel/LensHistoryFileProvider.java +++ b/lens-cli/src/main/java/org/apache/lens/cli/skel/LensHistoryFileProvider.java @@ -40,7 +40,7 @@ public class LensHistoryFileProvider extends DefaultHistoryFileNameProvider { * @see org.springframework.shell.plugin.support.DefaultHistoryFileNameProvider#name() */ @Override - public String name() { + public String getProviderName() { return "lens client history provider"; } } http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/skel/LensPromptProvider.java ---------------------------------------------------------------------- diff --git a/lens-cli/src/main/java/org/apache/lens/cli/skel/LensPromptProvider.java b/lens-cli/src/main/java/org/apache/lens/cli/skel/LensPromptProvider.java index e5524bd..3729bc7 100644 --- a/lens-cli/src/main/java/org/apache/lens/cli/skel/LensPromptProvider.java +++ b/lens-cli/src/main/java/org/apache/lens/cli/skel/LensPromptProvider.java @@ -41,7 +41,7 @@ public class LensPromptProvider extends DefaultPromptProvider { * @see org.springframework.shell.plugin.support.DefaultPromptProvider#name() */ @Override - public String name() { + public String getProviderName() { return "lens prompt provider"; } } http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/table/CollectionTable.java ---------------------------------------------------------------------- diff --git a/lens-cli/src/main/java/org/apache/lens/cli/table/CollectionTable.java b/lens-cli/src/main/java/org/apache/lens/cli/table/CollectionTable.java new file mode 100644 index 0000000..2f46c3b --- /dev/null +++ b/lens-cli/src/main/java/org/apache/lens/cli/table/CollectionTable.java @@ -0,0 +1,59 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.lens.cli.table; + + +import java.util.Collection; + +import org.springframework.shell.support.table.Table; +import org.springframework.shell.support.table.TableHeader; +import org.springframework.shell.support.table.TableRenderer; + +import lombok.Data; + +@Data +public class CollectionTable<T> { + private final Collection<T> collection; + private final RowProvider<T> provider; + private final String[] header; + + public CollectionTable(Collection<T> collection, RowProvider<T> provider, String... header) { + this.collection = collection; + this.provider = provider; + this.header = header; + } + + interface RowProvider<T> { + String[][] getRows(T element); + } + + @Override + public String toString() { + Table table = new Table(); + for (int i = 0; i < header.length; i++) { + table.addHeader(i + 1, new TableHeader(header[i])); + } + for (T element : collection) { + for (String[] row : provider.getRows(element)) { + table.addRow(row); + } + } + return TableRenderer.renderTextTable(table); + } +} http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/table/CollectionTableFactory.java ---------------------------------------------------------------------- diff --git a/lens-cli/src/main/java/org/apache/lens/cli/table/CollectionTableFactory.java b/lens-cli/src/main/java/org/apache/lens/cli/table/CollectionTableFactory.java new file mode 100644 index 0000000..bcc44a6 --- /dev/null +++ b/lens-cli/src/main/java/org/apache/lens/cli/table/CollectionTableFactory.java @@ -0,0 +1,158 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.lens.cli.table; + +import java.util.Comparator; +import java.util.List; + +import org.apache.lens.api.metastore.*; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + +public class CollectionTableFactory { + private CollectionTableFactory() {} + + public static CollectionTable<XFlattenedColumn> getCollectionTable(Class<? extends XField> claz, final String table) { + if (claz == XExprColumn.class) { + return new CollectionTable<>(Sets.newTreeSet(new Comparator<XFlattenedColumn>() { + @Override + public int compare(XFlattenedColumn o1, XFlattenedColumn o2) { + return o1.getExpression().getName().compareTo(o2.getExpression().getName()); + } + }), + new CollectionTable.RowProvider<XFlattenedColumn>() { + @Override + public String[][] getRows(XFlattenedColumn element) { + return new String[][]{ + { + nulltoBlank(element.getExpression().getName()), + nulltoBlank(element.getExpression().getDisplayString()), + nulltoBlank(element.getExpression().getDescription()), + expressionsAsString(element.getExpression().getExprSpec()), + }, + }; + } + + private String expressionsAsString(List<XExprSpec> exprSpec) { + StringBuilder sb = new StringBuilder(); + String sep = ""; + for (XExprSpec spec : exprSpec) { + sb.append(sep); + sep = ", "; + List<String> clauses = Lists.newArrayList(); + if (spec.getStartTime() != null) { + clauses.add("after " + spec.getStartTime()); + } + if (spec.getEndTime() != null) { + clauses.add("before " + spec.getEndTime()); + } + String sep1 = ""; + if (clauses.isEmpty()) { + clauses.add("always valid"); + } + for (String clause : clauses) { + sb.append(sep1).append(clause); + sep1 = " and "; + } + sb.append(": "); + sb.append(spec.getExpr()); + } + return sb.toString(); + } + }, "Name", "Display String", "Description", "Expr Specs"); + } else if (claz == XDimAttribute.class) { + return new CollectionTable<>(Sets.newTreeSet(new Comparator<XFlattenedColumn>() { + @Override + public int compare(XFlattenedColumn o1, XFlattenedColumn o2) { + if (o1 == null || o1.getDimAttribute() == null) { + return -1; + } else if (o2 == null || o2.getDimAttribute() == null) { + return 1; + } else if (table.equals(o1.getTableName()) && !table.equals(o2.getTableName())) { + return -1; + } else if (table.equals(o2.getTableName()) && !table.equals(o1.getTableName())) { + return 1; + } else { + if (o1.getTableName() == null) { + o1.setTableName(""); + } + if (o2.getTableName() == null) { + o2.setTableName(""); + } + if (o1.getChainName() == null) { + o1.setChainName(""); + } + if (o2.getChainName() == null) { + o2.setChainName(""); + } + int cmp = o1.getTableName().compareTo(o2.getTableName()); + if (cmp != 0) { + return cmp; + } + cmp = o1.getChainName().compareTo(o2.getChainName()); + if (cmp != 0) { + return cmp; + } + return o1.getDimAttribute().getName().compareTo(o2.getDimAttribute().getName()); + } + } + }), + new CollectionTable.RowProvider<XFlattenedColumn>() { + @Override + public String[][] getRows(XFlattenedColumn element) { + String prefix = XFlattenedColumnTable.firstNonNull(element.getChainName(), element.getTableName()); + return new String[][]{ + { + (prefix == null || prefix.isEmpty() || prefix.equalsIgnoreCase(table) ? "" : (prefix + ".")) + + nulltoBlank(element.getDimAttribute().getName()), + nulltoBlank(element.getDimAttribute().getDisplayString()), + nulltoBlank(element.getDimAttribute().getDescription()), + }, + }; + } + }, "Name", "Display String", "Description"); + } else if (claz == XMeasure.class) { + return new CollectionTable<>(Sets.newTreeSet(new Comparator<XFlattenedColumn>() { + @Override + public int compare(XFlattenedColumn o1, XFlattenedColumn o2) { + return o1.getMeasure().getName().compareTo(o2.getMeasure().getName()); + } + }), + new CollectionTable.RowProvider<XFlattenedColumn>() { + @Override + public String[][] getRows(XFlattenedColumn element) { + return new String[][]{ + { + nulltoBlank(element.getMeasure().getName()), + nulltoBlank(element.getMeasure().getDisplayString()), + nulltoBlank(element.getMeasure().getDescription()), + }, + }; + } + }, "Name", "Display String", "Description"); + } else { + return null; + } + } + + public static String nulltoBlank(String s) { + return s == null ? "" : s; + } +} http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/table/XFlattenedColumnTable.java ---------------------------------------------------------------------- diff --git a/lens-cli/src/main/java/org/apache/lens/cli/table/XFlattenedColumnTable.java b/lens-cli/src/main/java/org/apache/lens/cli/table/XFlattenedColumnTable.java new file mode 100644 index 0000000..d4208c1 --- /dev/null +++ b/lens-cli/src/main/java/org/apache/lens/cli/table/XFlattenedColumnTable.java @@ -0,0 +1,97 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.lens.cli.table; + + +import java.util.List; +import java.util.Map; + +import javax.xml.bind.annotation.XmlType; + +import org.apache.lens.api.metastore.XField; +import org.apache.lens.api.metastore.XFlattenedColumn; +import org.apache.lens.api.metastore.XFlattenedColumns; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; + +public class XFlattenedColumnTable { + private final String table; + Map<Class<? extends XField>, CollectionTable<XFlattenedColumn>> tables = Maps.newLinkedHashMap(); + List<String> chainNames = Lists.newArrayList(); + List<String> tableNames = Lists.newArrayList(); + + public XFlattenedColumnTable(XFlattenedColumns flattenedColumns, String table) { + this.table = table; + for (XFlattenedColumn column : flattenedColumns.getFlattenedColumn()) { + XField field = firstNonNull(column.getDimAttribute(), column.getMeasure(), column.getExpression()); + if (field != null) { + if (!tables.containsKey(field.getClass())) { + tables.put(field.getClass(), CollectionTableFactory.getCollectionTable(field.getClass(), table)); + } + tables.get(field.getClass()).getCollection().add(column); + } else { + if (column.getChainName() != null) { + chainNames.add(column.getChainName()); + } + if (column.getTableName() != null) { + tableNames.add(column.getTableName()); + } + } + } + } + + public static <T> T firstNonNull(T... args) { + for (T arg : args) { + if (arg != null) { + return arg; + } + } + return null; + } + + + @Override + public String toString() { + String sep = "============================="; + StringBuilder sb = new StringBuilder(); + for (Map.Entry<Class<? extends XField>, CollectionTable<XFlattenedColumn>> entry : tables.entrySet()) { + String title = + entry.getKey().getAnnotation(XmlType.class).name().replaceAll("^x_", "").replaceAll("_", " ") + "s"; + sb.append(title).append("\n").append(sep).append("\n").append(entry.getValue()).append("\n"); + } + String sep1 = ""; + if (!chainNames.isEmpty()) { + sb.append("Accessible Join Chains\n").append(sep).append("\n"); + for (String chain : chainNames) { + sb.append(sep1).append(chain); + sep1 = "\n"; + } + } + sep1 = ""; + if (!tableNames.isEmpty()) { + sb.append("Accessible Tables\n").append(sep).append("\n"); + for (String table : tableNames) { + sb.append(sep1).append(table); + sep1 = "\n"; + } + } + return sb.toString(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/main/java/org/apache/lens/cli/table/XJoinChainTable.java ---------------------------------------------------------------------- diff --git a/lens-cli/src/main/java/org/apache/lens/cli/table/XJoinChainTable.java b/lens-cli/src/main/java/org/apache/lens/cli/table/XJoinChainTable.java new file mode 100644 index 0000000..8082215 --- /dev/null +++ b/lens-cli/src/main/java/org/apache/lens/cli/table/XJoinChainTable.java @@ -0,0 +1,77 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.lens.cli.table; + + +import static org.apache.lens.cli.table.CollectionTableFactory.nulltoBlank; + +import org.apache.lens.api.metastore.*; + +public class XJoinChainTable { + + private XJoinChains xJoinChains; + + public XJoinChainTable(XJoinChains xJoinChains) { + this.xJoinChains = xJoinChains; + } + + @Override + public String toString() { + return new CollectionTable<>(xJoinChains.getJoinChain(), new CollectionTable.RowProvider<XJoinChain>() { + @Override + public String[][] getRows(XJoinChain element) { + int size = element.getPaths().getPath().size(); + String[][] ret = new String[size][5]; + for (int i = 0; i < size; i++) { + if (i == 0) { + ret[i][0] = nulltoBlank(element.getName()); + ret[i][1] = nulltoBlank(element.getDisplayString()); + ret[i][2] = nulltoBlank(element.getDescription()); + ret[i][3] = nulltoBlank(element.getDestTable()); + } else { + ret[i][0] = ""; + ret[i][1] = ""; + ret[i][2] = ""; + ret[i][3] = ""; + } + ret[i][4] = pathAsString(element.getPaths().getPath().get(i)); + } + return ret; + } + + private String pathAsString(XJoinPath path) { + StringBuilder sb = new StringBuilder(); + String sep1 = ""; + for (XJoinEdge edge : path.getEdges().getEdge()) { + sb.append(sep1) + .append(edge.getFrom().getTable()).append(".").append(edge.getFrom().getColumn()) + .append("=") + .append(edge.getTo().getTable()).append(".").append(edge.getTo().getColumn()); + sep1 = "->"; + } + return sb.toString(); + } + } + + , "Name", "Display String", "Description", "Destination Table", "Path"). + + toString(); + } +} + http://git-wip-us.apache.org/repos/asf/incubator-lens/blob/ff31ad96/lens-cli/src/test/java/org/apache/lens/cli/TestLensCubeCommands.java ---------------------------------------------------------------------- diff --git a/lens-cli/src/test/java/org/apache/lens/cli/TestLensCubeCommands.java b/lens-cli/src/test/java/org/apache/lens/cli/TestLensCubeCommands.java index ae39a2a..73661e1 100644 --- a/lens-cli/src/test/java/org/apache/lens/cli/TestLensCubeCommands.java +++ b/lens-cli/src/test/java/org/apache/lens/cli/TestLensCubeCommands.java @@ -18,15 +18,19 @@ */ package org.apache.lens.cli; +import static org.testng.Assert.*; + import java.io.*; import java.net.URL; +import java.util.Arrays; +import org.apache.lens.api.metastore.XJoinChains; import org.apache.lens.cli.commands.LensCubeCommands; +import org.apache.lens.cli.table.XJoinChainTable; import org.apache.lens.client.LensClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.testng.Assert; import org.testng.annotations.Test; /** @@ -51,22 +55,38 @@ public class TestLensCubeCommands extends LensCliApplicationTest { LOG.debug("Starting to test cube commands"); URL cubeSpec = TestLensCubeCommands.class.getClassLoader().getResource("sample-cube.xml"); String cubeList = command.showCubes(); - Assert.assertFalse(cubeList.contains("sample_cube")); + assertFalse(cubeList.contains("sample_cube")); command.createCube(new File(cubeSpec.toURI()).getAbsolutePath()); cubeList = command.showCubes(); - Assert.assertEquals(command.getLatest("sample_cube", "dt"), "No Data Available"); - Assert.assertTrue(cubeList.contains("sample_cube")); - + assertEquals(command.getLatest("sample_cube", "dt"), "No Data Available"); + assertTrue(cubeList.contains("sample_cube")); + testJoinChains(command); + testFields(command); testUpdateCommand(new File(cubeSpec.toURI()), command); command.dropCube("sample_cube"); try { command.getLatest("sample_cube", "dt"); - Assert.fail("should have failed as cube doesn't exist"); + fail("should have failed as cube doesn't exist"); } catch (Exception e) { //pass } cubeList = command.showCubes(); - Assert.assertFalse(cubeList.contains("sample_cube")); + assertFalse(cubeList.contains("sample_cube")); + } + + private void testJoinChains(LensCubeCommands command) { + String joinChains = command.showJoinChains("sample_cube"); + assertEquals(joinChains, new XJoinChainTable(new XJoinChains()).toString()); + } + + private void testFields(LensCubeCommands command) { + String fields = command.showQueryableFields("sample_cube", true); + for (String field : Arrays + .asList("dim1", "dim2", "dim3", "measure1", "measure2", "measure3", "measure4", "expr_msr5")) { + assertTrue(fields.contains(field)); + } + assertTrue(fields.contains("measure3 + measure4 + 0.01")); + assertTrue(fields.replace("measure3 + measure4 + 0.01", "blah").contains("measure3 + measure4")); } /** @@ -105,13 +125,13 @@ public class TestLensCubeCommands extends LensCliApplicationTest { String propString = "name : sample_cube.prop value : sample"; String propString1 = "name : sample_cube.prop1 value : sample1"; - Assert.assertTrue(desc.contains(propString)); + assertTrue(desc.contains(propString)); command.updateCube("sample_cube", "/tmp/sample_cube1.xml"); desc = command.describeCube("sample_cube"); LOG.debug(desc); - Assert.assertTrue(desc.contains(propString)); - Assert.assertTrue(desc.contains(propString1)); + assertTrue(desc.contains(propString)); + assertTrue(desc.contains(propString1)); } finally { newFile.delete(); }
