This is an automated email from the ASF dual-hosted git repository.

sergeykamov pushed a commit to branch NLPCRAFT-30
in repository https://gitbox.apache.org/repos/asf/incubator-nlpcraft.git


The following commit(s) were added to refs/heads/NLPCRAFT-30 by this push:
     new fb807ae  WIP.
fb807ae is described below

commit fb807aed7786c8df718158c9d0d19236f3dfef7a
Author: Sergey Kamov <[email protected]>
AuthorDate: Wed Apr 8 16:55:50 2020 +0300

    WIP.
---
 .../nlpcraft/examples/sql/db/SqlBuilder.scala      |  45 ++++++-
 .../nlpcraft/model/tools/sqlgen/NCSqlSort.java     |   2 +-
 .../model/tools/sqlgen/impl/NCSqlBeans.scala       |  32 ++++-
 .../tools/sqlgen/impl/NCSqlExtractorImpl.scala     | 144 +++++++++++----------
 .../tools/sqlgen/impl/NCSqlSchemaBuilderImpl.scala |  87 +++++++------
 5 files changed, 186 insertions(+), 124 deletions(-)

diff --git 
a/src/main/scala/org/apache/nlpcraft/examples/sql/db/SqlBuilder.scala 
b/src/main/scala/org/apache/nlpcraft/examples/sql/db/SqlBuilder.scala
index 44d32d8..1fea753 100644
--- a/src/main/scala/org/apache/nlpcraft/examples/sql/db/SqlBuilder.scala
+++ b/src/main/scala/org/apache/nlpcraft/examples/sql/db/SqlBuilder.scala
@@ -72,7 +72,23 @@ case class SqlBuilder(schema: NCSqlSchema) extends 
LazyLogging {
 
     private def sql(clause: NCSqlTable): String = clause.getTable
     private def sql(clause: NCSqlColumn): String = 
s"${clause.getTable}.${clause.getColumn}"
-    private def sql(clause: NCSqlSort): String = s"${sql(clause.getColumn)} 
${if (clause.isAscending) "ASC" else "DESC"}"
+    private def sql(clause: NCSqlSort): String = {
+        val cols: Seq[NCSqlColumn] =
+            if (clause.getBy.isEmpty) {
+                require(!clause.getSubj.isEmpty)
+
+                clause.getSubj.asScala.flatMap(tab ⇒ {
+                    val cols = tab.getColumns.asScala
+                    val pkCols = cols.filter(_.isPk)
+
+                    if (pkCols.nonEmpty) pkCols else cols.take(1)
+                })
+            }
+            else
+                clause.getBy.asScala
+
+        cols.map(col ⇒ s"${sql(col)} ${if (clause.isAscending) "ASC" else 
"DESC"}").mkString(", ")
+    }
 
     // TODO: implement based on join type.
     private def sql(clause: NCSqlJoin): String =
@@ -125,12 +141,20 @@ case class SqlBuilder(schema: NCSqlSchema) extends 
LazyLogging {
         sorts.size match {
             case 0 ⇒
                 limit.flatMap(l ⇒ if (cols.contains(l.getColumn)) 
Some(Seq(limit2Sort(l))) else None).
-                    getOrElse({
+                    getOrElse(
                         tables.flatMap(_.getDefaultSort.asScala.
-                            // 'Sort' can contains columns from select list 
only (some databases restriction)
-                            flatMap(sort ⇒ if (cols.contains(sort.getColumn)) 
Some(sort) else None)
+                            // 'Sort' can contain columns from select list 
only (some databases restriction)
+                            flatMap(sort ⇒
+                                if (
+                                    
sort.getSubj.asScala.toSet.subsetOf(tables.toSet) &&
+                                    (sort.getBy.isEmpty || 
sort.getBy.asScala.toSet.subsetOf(cols.toSet))
+                                )
+                                    Some(sort)
+                                else
+                                    None
+                            )
                         )
-                    }).distinct
+                    ).distinct
             case _ ⇒ sorts.distinct
         }
 
@@ -159,7 +183,11 @@ case class SqlBuilder(schema: NCSqlSchema) extends 
LazyLogging {
         }
     }
 
-    private def limit2Sort(l: NCSqlLimit): NCSqlSort = 
NCSqlSortImpl(l.getColumn, l.isAscending)
+    private def limit2Sort(l: NCSqlLimit): NCSqlSort = NCSqlSortImpl(
+        Seq(schemaTabsByNames(l.getColumn.getTable)),
+        Seq(l.getColumn),
+        l.isAscending
+    )
 
     private def sort(cols2Sort: Seq[NCSqlColumn], cols: Seq[NCSqlColumn], 
tabs: Seq[NCSqlTable]): Seq[NCSqlColumn] =
         cols2Sort.sortBy(col ⇒
@@ -277,7 +305,10 @@ case class SqlBuilder(schema: NCSqlSchema) extends 
LazyLogging {
 
         colsNorm.foreach(col ⇒ tabsNorm += schemaTabsByNames(col.getTable))
         condsNorm.foreach(cond ⇒ { tabsNorm += 
schemaTabsByNames(cond.column.getTable); colsNorm += cond.column })
-        sortsNorm.foreach(sort ⇒ { tabsNorm += 
schemaTabsByNames(sort.getColumn.getTable); colsNorm += sort.getColumn })
+        sortsNorm.foreach(sort ⇒ {
+            tabsNorm ++= sort.getSubj.asScala ++ sort.getBy.asScala.map(col ⇒ 
schemaTabsByNames(col.getTable))
+            colsNorm ++= sort.getBy.asScala
+        })
 
         val freeDateColOpt = findDateColumn(tabsNorm)
 
diff --git 
a/src/main/scala/org/apache/nlpcraft/model/tools/sqlgen/NCSqlSort.java 
b/src/main/scala/org/apache/nlpcraft/model/tools/sqlgen/NCSqlSort.java
index dc92395..74c0a4e 100644
--- a/src/main/scala/org/apache/nlpcraft/model/tools/sqlgen/NCSqlSort.java
+++ b/src/main/scala/org/apache/nlpcraft/model/tools/sqlgen/NCSqlSort.java
@@ -31,7 +31,7 @@ public interface NCSqlSort {
     /**
      * TODO:
      */
-    List<NCSqlColumn> getSubj();
+    List<NCSqlTable> getSubj();
 
     /**
      * TODO:
diff --git 
a/src/main/scala/org/apache/nlpcraft/model/tools/sqlgen/impl/NCSqlBeans.scala 
b/src/main/scala/org/apache/nlpcraft/model/tools/sqlgen/impl/NCSqlBeans.scala
index adc77e4..ecd34a4 100644
--- 
a/src/main/scala/org/apache/nlpcraft/model/tools/sqlgen/impl/NCSqlBeans.scala
+++ 
b/src/main/scala/org/apache/nlpcraft/model/tools/sqlgen/impl/NCSqlBeans.scala
@@ -35,7 +35,13 @@ import scala.compat.java8.OptionConverters._
   * @param isPk
   * @param isNullable
   */
-case class NCSqlColumnImpl(table: String, column: String, dataType: Int, isPk: 
Boolean, isNullable: Boolean) extends NCSqlColumn {
+case class NCSqlColumnImpl(
+    table: String,
+    column: String,
+    dataType: Int,
+    isPk: Boolean,
+    isNullable: Boolean
+) extends NCSqlColumn {
     override def getTable: String = table
     override def getColumn: String = column
     override def getDataType: Int = dataType
@@ -59,7 +65,13 @@ case class NCSqlDateRangeImpl(from: Timestamp, to: 
Timestamp) extends NCSqlDateR
   * @param toColumns
   * @param typ
   */
-case class NCSqlJoinImpl(fromTable: String, toTable: String, fromColumns: 
Seq[String], toColumns: Seq[String], typ: NCSqlJoinType) extends NCSqlJoin {
+case class NCSqlJoinImpl(
+    fromTable: String,
+    toTable: String,
+    fromColumns: Seq[String],
+    toColumns: Seq[String],
+    typ: NCSqlJoinType
+) extends NCSqlJoin {
     override def getFromTable: String = fromTable
     override def getToTable: String = toTable
     override def getFromColumns: util.List[String] = fromColumns.asJava
@@ -73,8 +85,8 @@ case class NCSqlJoinImpl(fromTable: String, toTable: String, 
fromColumns: Seq[St
  * @param by
  * @param asc
  */
-case class NCSqlSortImpl(subj: Seq[NCSqlColumn], by: Seq[NCSqlColumn], asc: 
Boolean) extends NCSqlSort {
-    override def getSubj: util.List[NCSqlColumn] = subj.asJava
+case class NCSqlSortImpl(subj: Seq[NCSqlTable], by: Seq[NCSqlColumn], asc: 
Boolean) extends NCSqlSort {
+    override def getSubj: util.List[NCSqlTable] = subj.asJava
     override def getBy: util.List[NCSqlColumn] = by.asJava
     override def isAscending: Boolean = asc
 }
@@ -88,13 +100,23 @@ case class NCSqlSortImpl(subj: Seq[NCSqlColumn], by: 
Seq[NCSqlColumn], asc: Bool
   * @param extraTables
   * @param defaultDate
   */
-case class NCSqlTableImpl(table: String, columns: Seq[NCSqlColumn], sort: 
Seq[NCSqlSort], select: Seq[String], extraTables: Seq[String], defaultDate: 
Option[NCSqlColumn]) extends NCSqlTable {
+case class NCSqlTableImpl(
+    table: String,
+    columns: Seq[NCSqlColumn],
+    sort: mutable.ArrayBuffer[NCSqlSort] = mutable.ArrayBuffer.empty,
+    select: Seq[String],
+    extraTables: Seq[String],
+    defaultDate: Option[NCSqlColumn]
+) extends NCSqlTable {
     override def getTable: String = table
     override def getColumns: util.List[NCSqlColumn] = columns.asJava
     override def getDefaultSort: util.List[NCSqlSort] = sort.asJava
     override def getDefaultSelect: util.List[String] = select.asJava
     override def getExtraTables: util.List[String] = extraTables.asJava
     override def getDefaultDate: Optional[NCSqlColumn] = defaultDate.asJava
+
+    // TODO: what about another fields for symmetry.
+    def addSort(sort: NCSqlSort): Unit = this.sort += sort
 }
 
 /**
diff --git 
a/src/main/scala/org/apache/nlpcraft/model/tools/sqlgen/impl/NCSqlExtractorImpl.scala
 
b/src/main/scala/org/apache/nlpcraft/model/tools/sqlgen/impl/NCSqlExtractorImpl.scala
index e29648a..299b373 100644
--- 
a/src/main/scala/org/apache/nlpcraft/model/tools/sqlgen/impl/NCSqlExtractorImpl.scala
+++ 
b/src/main/scala/org/apache/nlpcraft/model/tools/sqlgen/impl/NCSqlExtractorImpl.scala
@@ -21,8 +21,8 @@ import java.sql.Timestamp
 import java.util
 
 import org.apache.nlpcraft.common.NCException
-import org.apache.nlpcraft.model.tools.sqlgen._
 import org.apache.nlpcraft.model._
+import org.apache.nlpcraft.model.tools.sqlgen._
 
 import scala.collection.JavaConverters._
 import scala.compat.java8.OptionConverters._
@@ -110,32 +110,80 @@ class NCSqlExtractorImpl(schema: NCSqlSchema, variant: 
NCVariant) extends NCSqlE
     }
 
     /**
-      *
-      * @param refTok
-      * @return
-      */
-    private def getReference(refTok: NCToken): Option[NCSqlColumn] = {
-        val tok = getLinks(variant, refTok)
-
-        findAnyColumnTokenOpt(tok) match {
+     *
+     * @param link
+     * @param typ
+     * @return
+     */
+    private def findColumn(link: NCToken, typ: String): NCSqlColumn =
+        findAnyColumnTokenOpt(link) match {
             // If reference is column - sort by column.
-            case Some(t) ⇒ Some(extractColumn(t))
+            case Some(t) ⇒ extractColumn(t)
             case None ⇒
                 // If reference is table - sort by any PK column of table.
-                findAnyTableTokenOpt(tok) match {
-                    case Some(tab) ⇒ Some(tab.getColumns.asScala.minBy(col ⇒ 
if (col.isPk) 0 else 1))
-                    case None ⇒ None
+                findAnyTableTokenOpt(link) match {
+                    case Some(tab) ⇒ tab.getColumns.asScala.minBy(col ⇒ if 
(col.isPk) 0 else 1)
+                    case None ⇒ throw new NCException(s"Unexpected $typ link: 
$link")
                 }
         }
+
+    /**
+     *
+     * @param link
+     * @param typ
+     * @return
+     */
+    private def findTable(link: NCToken, typ: String): NCSqlTable =
+        findAnyTableTokenOpt(link) match {
+            case Some(t) ⇒ t
+            case None ⇒
+                findAnyColumnTokenOpt(link) match {
+                    case Some(col) ⇒ 
findSchemaTable(extractColumn(col).getTable)
+                    case None ⇒ throw new NCException(s"Unexpected $typ link: 
$link")
+                }
+        }
+
+    /**
+     *
+     * @param variant
+     * @param tok
+     * @return
+     */
+    private def getLinks(
+        variant: NCVariant, tok: NCToken, idxField: String, noteField: String, 
canBeEmpty: Boolean
+    ): Seq[NCToken] = {
+        val idxsOpt: Option[util.List[Integer]] = 
tok.metaOpt(s"${tok.getId}:$idxField").asScala
+
+        if (idxsOpt.isEmpty && !canBeEmpty)
+            throw new NCException(s"Empty indexes for: $tok")
+
+        idxsOpt.get.asScala.map(idx ⇒ {
+            if (idx < variant.size) {
+                val note: String = tok.metax(s"${tok.getId}:$noteField")
+
+                val link = variant.get(idx)
+
+                if (link.getId != note)
+                    throw new NCException(s"Unexpected token with index: $idx, 
type: $note")
+
+                link
+            }
+            else
+                throw new NCException(s"Token not found with index: $idx")
+        })
     }
 
     /**
      *
-     * @param refToks
+     * @param tok
+     * @param metaName
+     * @param dflt
      * @return
      */
-    private def getReferences(refToks: Seq[NCToken]): Seq[NCSqlColumn] = {
-        refToks
+    private def getAsc(tok: NCToken, metaName: String, dflt: Boolean): Boolean 
= {
+        val ascOpt: Option[Boolean] = tok.meta(metaName)
+
+        ascOpt.getOrElse(dflt)
     }
 
     /**
@@ -146,34 +194,18 @@ class NCSqlExtractorImpl(schema: NCSqlSchema, variant: 
NCVariant) extends NCSqlE
     override def extractLimit(limitTok: NCToken): NCSqlLimit = {
         checkTokenId(limitTok, "nlpcraft:limit")
         
-        // Skips indexes to simplify.
-        val limit: Double = limitTok.metax("nlpcraft:limit:limit")
-
         val links = getLinks(variant, limitTok, "indexes", "note", false)
 
-        val size = links.size
-
-        size match {
+        links.size match {
             case 1 ⇒
-                val link = links.head
-
-                val res = findAnyColumnTokenOpt(link) match {
-                    // If reference is column - sort by column.
-                    case Some(t) ⇒ extractColumn(t)
-                    case None ⇒
-                        // If reference is table - sort by any PK column of 
table.
-                        findAnyTableTokenOpt(link) match {
-                            case Some(tab) ⇒ tab.getColumns.asScala.minBy(col 
⇒ if (col.isPk) 0 else 1)
-                            case None ⇒ throw new NCException("TODO:")
-                        }
-                }
+                val limit: Double = limitTok.metax("nlpcraft:limit:limit")
 
                 NCSqlLimitImpl(
-                    res,
+                    findColumn(links.head, "LIMIT"),
                     limit.intValue(),
-                    limitTok.metax("nlpcraft:limit:asc")
+                    getAsc(limitTok, "nlpcraft:limit:asc", true)
                 )
-            case  _ ⇒ throw new NCException(s"Unexpected LIMIT links count: 
$size")
+            case n ⇒ throw new NCException(s"Unexpected LIMIT links count: $n")
         }
     }
     
@@ -184,10 +216,13 @@ class NCSqlExtractorImpl(schema: NCSqlSchema, variant: 
NCVariant) extends NCSqlE
       */
     override def extractSort(sortTok: NCToken): NCSqlSort = {
         checkTokenId(sortTok, "nlpcraft:sort")
-        
+
         NCSqlSortImpl(
-            getReference(sortTok).getOrElse(throw new NCException(s"Sort not 
found for: $sortTok")),
-            sortTok.metax("nlpcraft:sort:asc")
+            getLinks(variant, sortTok, "subjindexes", "subjnotes", false).
+                map(link ⇒ findTable(link, "SORT")),
+            getLinks(variant, sortTok, "byindexes", "bynotes", true).
+                map(link ⇒ findColumn(link, "SORT BY")),
+            getAsc(sortTok, "nlpcraft:sort:asc", true)
         )
     }
     
@@ -229,33 +264,4 @@ class NCSqlExtractorImpl(schema: NCSqlSchema, variant: 
NCVariant) extends NCSqlE
             new Timestamp(tok.metax("nlpcraft:date:to"))
         )
     }
-    
-    /**
-      * 
-      * @param variant
-      * @param tok
-      * @return
-      */
-    private def getLinks(variant: NCVariant, tok: NCToken, idxField: String, 
noteField: String, canBeEmpty: Boolean): Seq[NCToken] = {
-        val idxsOpt: Option[util.List[Integer]] = 
tok.metaOpt(s"${tok.getId}:$idxField").asScala
-        
-        if (idxsOpt.isEmpty && !canBeEmpty)
-            throw new NCException(s"Empty indexes for: $tok")
-
-        idxsOpt.get.asScala.map(idx ⇒ {
-            if (idx < variant.size) {
-                val note: String = tok.metax(s"${tok.getId}:$noteField")
-
-                val link = variant.get(idx)
-
-                if (link.getId != note)
-                    throw new NCException(s"Unexpected token with index: $idx, 
type: $note")
-
-                link
-            }
-            else
-                throw new NCException(s"Token not found with index: $idx")
-        })
-
-    }
 }
diff --git 
a/src/main/scala/org/apache/nlpcraft/model/tools/sqlgen/impl/NCSqlSchemaBuilderImpl.scala
 
b/src/main/scala/org/apache/nlpcraft/model/tools/sqlgen/impl/NCSqlSchemaBuilderImpl.scala
index 7899d00..b30a4e1 100644
--- 
a/src/main/scala/org/apache/nlpcraft/model/tools/sqlgen/impl/NCSqlSchemaBuilderImpl.scala
+++ 
b/src/main/scala/org/apache/nlpcraft/model/tools/sqlgen/impl/NCSqlSchemaBuilderImpl.scala
@@ -81,49 +81,14 @@ object NCSqlSchemaBuilderImpl {
 
                     val cols = tabCols(tab).toSeq.sortBy(p ⇒ (if (p.isPk) 0 
else 1, p.getColumn)).asJava
                     
-                    val table: NCSqlTable = NCSqlTableImpl(
-                        tab,
+                    val table: NCSqlTableImpl = NCSqlTableImpl(
+                        table = tab,
                         // TODO: columns should be list, but elements are set. 
How should we order them?
                         // TODO: Seems elements should be seq too in model.
-                        cols.asScala,
-                        dfltSort.
-                            map(s ⇒ {
-                                def error() = throw new NCException(s"Invalid 
default sort declaration in: $s")
-                                
-                                var pair = s.split("\\.")
-                                
-                                val t =
-                                    pair.length match {
-                                        case 1 ⇒
-                                            pair = s.split("#")
-                                            
-                                            // By default, same table name.
-                                            tab
-                                        case 2 ⇒
-                                            val t = pair.head
-                                            
-                                            pair = pair.last.split("#")
-                                            
-                                            t
-                                        case  _ ⇒ error()
-                                    }
-                                
-                                if (pair.length != 2)
-                                    error()
-                                
-                                val col = pair.head
-                                val asc = pair.last.toLowerCase
-                                
-                                if (asc != "asc" && asc != "desc")
-                                    error()
-                                
-                                val sort: NCSqlSort = 
NCSqlSortImpl(findSchemaColumn(cols, t, col), asc == "asc")
-                                
-                                sort
-                            }),
-                        dfltSelect,
-                        extra,
-                        defDateOpt match {
+                        columns = cols.asScala,
+                        select = dfltSelect,
+                        extraTables = extra,
+                        defaultDate = defDateOpt match {
                             case Some(defDate) ⇒
                                 def error() = throw new NCException(s"Invalid 
default date declaration in: $defDate")
 
@@ -139,7 +104,45 @@ object NCSqlSchemaBuilderImpl {
                             case None ⇒ None
                         }
                     )
-                    
+
+                    dfltSort.
+                        foreach(s ⇒ {
+                            def error() = throw new NCException(s"Invalid 
default sort declaration in: $s")
+
+                            var pair = s.split("\\.")
+
+                            val t =
+                                pair.length match {
+                                    case 1 ⇒
+                                        pair = s.split("#")
+
+                                        // By default, same table name.
+                                        tab
+                                    case 2 ⇒
+                                        val t = pair.head
+
+                                        pair = pair.last.split("#")
+
+                                        t
+                                    case  _ ⇒ error()
+                                }
+
+                            if (pair.length != 2)
+                                error()
+
+                            val col = pair.head
+                            val asc = pair.last.toLowerCase
+
+                            if (asc != "asc" && asc != "desc")
+                                error()
+
+                            table.addSort(NCSqlSortImpl(
+                                Seq(table),
+                                Seq(findSchemaColumn(cols, t, col)),
+                                asc == "asc"
+                            ))
+                        })
+
                     table
                 }).toSeq
     

Reply via email to