@@ -3,6 +3,7 @@ package io.hasura.oracle
33import io.hasura.ndc.common.ConnectorConfiguration
44import io.hasura.ndc.common.NDCScalar
55import io.hasura.ndc.ir.*
6+ import io.hasura.ndc.ir.Type
67import io.hasura.ndc.ir.Field.ColumnField
78import io.hasura.ndc.ir.Field as IRField
89import io.hasura.ndc.sqlgen.BaseQueryGenerator
@@ -19,23 +20,88 @@ object JsonQueryGenerator : BaseQueryGenerator() {
1920 }
2021
2122 override fun queryRequestToSQL (request : QueryRequest ): Select <* > {
22- return queryRequestToSQLInternal2(request)
23+ return mkNativeQueryCTEs(request).select(
24+ DSL .jsonArrayAgg(
25+ buildJSONSelectionForQueryRequest(request)
26+ ).returning(
27+ SQLDataType .CLOB
28+ )
29+ )
2330 }
2431
25- fun queryRequestToSQLInternal2 (
32+ fun buildJSONSelectionForQueryRequest (
2633 request : QueryRequest ,
2734 parentTable : String? = null,
28- parentRelationship : Relationship ? = null,
29- ): SelectHavingStep <Record1 <JSON >> {
30- val isRootQuery = parentRelationship == null
31-
32- return DSL .select(
33- DSL .jsonObject(
34- buildList {
35- if (! request.query.fields.isNullOrEmpty()) {
36- add(
37- DSL .jsonEntry(
38- " rows" ,
35+ parentRelationship : Relationship ? = null
36+ ): JSONObjectNullStep <* > {
37+
38+ val baseSelection = DSL .select(
39+ DSL .table(DSL .name(request.collection)).asterisk()
40+ ).from(
41+ if (request.query.predicate == null ) {
42+ DSL .table(DSL .name(request.collection))
43+ } else {
44+ val table = DSL .table(DSL .name(request.collection))
45+ val requiredJoinTables = collectRequiredJoinTablesForWhereClause(
46+ where = request.query.predicate!! ,
47+ collectionRelationships = request.collection_relationships
48+ )
49+ requiredJoinTables.foldIndexed(table) { index, acc, relationship ->
50+ val parentTable = if (index == 0 ) {
51+ request.collection
52+ } else {
53+ requiredJoinTables.elementAt(index - 1 ).target_collection
54+ }
55+
56+ val joinTable = DSL .table(DSL .name(relationship.target_collection))
57+ acc.join(joinTable).on(
58+ mkJoinWhereClause(
59+ sourceTable = parentTable,
60+ parentRelationship = relationship
61+ )
62+ )
63+ }
64+ }
65+ ).apply {
66+ if (request.query.predicate != null ) {
67+ where(getWhereConditions(request))
68+ }
69+ if (parentRelationship != null ) {
70+ where(
71+ mkJoinWhereClause(
72+ sourceTable = parentTable ? : error(" parentTable is null" ),
73+ parentRelationship = parentRelationship
74+ )
75+ )
76+ }
77+ if (request.query.order_by != null ) {
78+ orderBy(
79+ translateIROrderByField(
80+ orderBy = request.query.order_by,
81+ currentCollection = getTableName(request.collection),
82+ relationships = request.collection_relationships
83+ )
84+ )
85+ }
86+ if (request.query.limit != null ) {
87+ limit(request.query.limit)
88+ }
89+ if (request.query.offset != null ) {
90+ offset(request.query.offset)
91+ }
92+ }.apply {
93+ addJoinsRequiredForOrderByFields(this , request)
94+ }.asTable(
95+ DSL .name(getTableName(request.collection))
96+ )
97+
98+ return DSL .jsonObject(
99+ buildList {
100+ if (! request.query.fields.isNullOrEmpty()) {
101+ add(
102+ DSL .jsonEntry(
103+ " rows" ,
104+ DSL .select(
39105 DSL .jsonArrayAgg(
40106 DSL .jsonObject(
41107 (request.query.fields ? : emptyMap()).map { (alias, field) ->
@@ -55,7 +121,7 @@ object JsonQueryGenerator : BaseQueryGenerator() {
55121 request.collection_relationships[field.relationship]
56122 ? : error(" Relationship ${field.relationship} not found" )
57123
58- val subQuery = queryRequestToSQLInternal2 (
124+ val subQuery = buildJSONSelectionForQueryRequest (
59125 parentTable = request.collection,
60126 parentRelationship = relationship,
61127 request = QueryRequest (
@@ -70,9 +136,8 @@ object JsonQueryGenerator : BaseQueryGenerator() {
70136 DSL .jsonEntry(
71137 alias,
72138 DSL .coalesce(
73- DSL .select(
74- subQuery.asField<Any >(alias)
75- ), DSL .jsonObject(
139+ DSL .select(subQuery),
140+ DSL .jsonObject(
76141 DSL .jsonEntry(
77142 " rows" ,
78143 DSL .jsonArray().returning(SQLDataType .CLOB )
@@ -84,109 +149,37 @@ object JsonQueryGenerator : BaseQueryGenerator() {
84149 }
85150 }
86151 ).returning(SQLDataType .CLOB )
87- ).apply {
88- if (request.query.order_by != null ) {
89- orderBy(
90- translateIROrderByField(
91- orderBy = request.query.order_by,
92- currentCollection = getTableName(request.collection),
93- relationships = request.collection_relationships
94- )
95- )
96- }
97- }.returning(SQLDataType .CLOB )
152+ ).returning(SQLDataType .CLOB )
153+ ).from(
154+ baseSelection
98155 )
99156 )
100- }
101- if (! request.query.aggregates.isNullOrEmpty()) {
102- add(
103- DSL .jsonEntry(
104- " aggregates" ,
157+ )
158+ }
159+ if (! request.query.aggregates.isNullOrEmpty()) {
160+ add(
161+ DSL .jsonEntry(
162+ " aggregates" ,
163+ DSL .select(
105164 DSL .jsonObject(
106165 (request.query.aggregates ? : emptyMap()).map { (alias, aggregate) ->
107166 DSL .jsonEntry(
108167 alias,
109168 getAggregatejOOQFunction(aggregate)
110169 )
111170 }
112- )
113- )
114- )
115- }
116- }
117- ).returning(SQLDataType .CLOB ).let {
118- when {
119- isRootQuery -> DSL .jsonArrayAgg(it).returning(SQLDataType .CLOB )
120- else -> it
121- }
122- }
123- ).from(
124- DSL .select(
125- DSL .table(DSL .name(request.collection))
126- .asterisk()
127- ).from(
128- run<Table <Record >> {
129- val table = DSL .table(DSL .name(request.collection))
130- if (request.query.predicate == null ) {
131- table
132- } else {
133- val requiredJoinTables = collectRequiredJoinTablesForWhereClause(
134- where = request.query.predicate!! ,
135- collectionRelationships = request.collection_relationships
136- )
137-
138- requiredJoinTables.foldIndexed(table) { index, acc, relationship ->
139- val parentTable = if (index == 0 ) {
140- request.collection
141- } else {
142- requiredJoinTables.elementAt(index - 1 ).target_collection
143- }
144-
145- val joinTable = DSL .table(DSL .name(relationship.target_collection))
146- acc.join(joinTable).on(
147- mkJoinWhereClause(
148- sourceTable = parentTable,
149- parentRelationship = relationship
150- )
171+ ).returning(SQLDataType .CLOB )
172+ ).from(
173+ baseSelection
151174 )
152- }
153- }
154- }
155- ).apply {
156- if (request.query.predicate != null ) {
157- where(getWhereConditions(request))
158- }
159- if (parentRelationship != null ) {
160- where(
161- mkJoinWhereClause(
162- sourceTable = parentTable ? : error(" parentTable is null" ),
163- parentRelationship = parentRelationship
164- )
165- )
166- }
167- if (request.query.order_by != null ) {
168- orderBy(
169- translateIROrderByField(
170- orderBy = request.query.order_by,
171- currentCollection = getTableName(request.collection),
172- relationships = request.collection_relationships
173175 )
174176 )
175177 }
176- if (request.query.limit != null ) {
177- limit(request.query.limit)
178- }
179- if (request.query.offset != null ) {
180- offset(request.query.offset)
181- }
182- }.asTable(
183- DSL .name(getTableName(request.collection))
184- )
185- ).groupBy(
186- DSL .nullCondition()
187- )
178+ }
179+ ).returning(SQLDataType .CLOB ) as JSONObjectNullStep <* >
188180 }
189-
181+
182+
190183 fun collectRequiredJoinTablesForWhereClause (
191184 where : Expression ,
192185 collectionRelationships : Map <String , Relationship >,
@@ -223,13 +216,37 @@ object JsonQueryGenerator : BaseQueryGenerator() {
223216 private fun columnTypeTojOOQType (collection : String , field : ColumnField ): org.jooq.DataType <out Any > {
224217 val connectorConfig = ConnectorConfiguration .Loader .config
225218
226- val table = connectorConfig.tables.find { it.tableName == collection }
227- ? : error(" Table $collection not found in connector configuration" )
219+ val collectionIsTable = connectorConfig.tables.any { it.tableName == collection }
220+ val collectionIsNativeQuery = connectorConfig.nativeQueries.containsKey(collection)
221+
222+ if (! collectionIsTable && ! collectionIsNativeQuery) {
223+ error(" Collection $collection not found in connector configuration" )
224+ }
225+
226+ val scalarType = when {
227+ collectionIsTable -> {
228+ val table = connectorConfig.tables.find { it.tableName == collection }
229+ ? : error(" Table $collection not found in connector configuration" )
230+
231+ val column = table.columns.find { it.name == field.column }
232+ ? : error(" Column ${field.column} not found in table $collection " )
228233
229- val column = table.columns.find { it.name == field.column }
230- ? : error(" Column ${field.column} not found in table $collection " )
234+ OracleJDBCSchemaGenerator .mapScalarType(column.type, column.numeric_scale)
235+ }
236+
237+ collectionIsNativeQuery -> {
238+ val nativeQuery = connectorConfig.nativeQueries[collection]
239+ ? : error(" Native query $collection not found in connector configuration" )
240+
241+ val column = nativeQuery.columns[field.column]
242+ ? : error(" Column ${field.column} not found in native query $collection " )
243+
244+ OracleJDBCSchemaGenerator .mapScalarType(Type .extractBaseType(column), null )
245+ }
246+
247+ else -> error(" Collection $collection not found in connector configuration" )
248+ }
231249
232- val scalarType = OracleJDBCSchemaGenerator .mapScalarType(column.type, column.numeric_scale)
233250 return when (scalarType) {
234251 NDCScalar .BOOLEAN -> SQLDataType .BOOLEAN
235252 NDCScalar .INT -> SQLDataType .INTEGER
0 commit comments