22 * COPYRIGHT: See COPYING in the top level directory
33 * PROJECT: SqliteHelper
44 * FILE: SqliteHelper/SqLiteDataTypes.cs
5- * PURPOSE: Enums of Types Sqlite Supports
5+ * PURPOSE: Enums of Types Sqlite Supports and Syntax Checking
66 * PROGRAMER: Peter Geinitz (Wayfarer)
77 */
88
99using System ;
10- using System . Collections ;
1110using System . Collections . Generic ;
1211using System . Linq ;
1312
1413namespace SqliteHelper
1514{
15+ /// <summary>
16+ /// Handles syntax checking and data validation for SQLite operations
17+ /// </summary>
1618 internal sealed class SqliteSyntax
1719 {
1820 /// <summary>
@@ -35,35 +37,49 @@ public SqliteSyntax(EventHandler<MessageItem> setMessage = null)
3537 }
3638
3739 /// <summary>
38- /// Basic sanity checks
40+ /// Basic sanity checks.
41+ /// Refactored to check the Entire Row against the Entire Schema.
3942 /// </summary>
4043 /// <param name="tableInfo">Headers, Data Type and Constraints of the table</param>
41- /// <param name="table">Table Collection</param>
42- /// <param name="row">Table Collection</param>
43- /// <param name="convert">Table Collection</param>
44+ /// <param name="row">The specific Row we are checking</param>
45+ /// <param name="batch">The full batch of rows (needed for uniqueness checks within the batch)</param>
4446 /// <returns>true if no errors were found</returns>
45- internal bool AdvancedSyntaxCheck ( ICollection tableInfo , IEnumerable < TableSet > table , TableSet row ,
46- TableColumns convert )
47+ internal bool AdvancedSyntaxCheck (
48+ Dictionary < string , TableColumns > tableInfo ,
49+ TableSet row ,
50+ IEnumerable < TableSet > batch )
4751 {
48- if ( tableInfo . Count != table . First ( ) . Row . Count )
52+ // Sanity Check: Do the column counts match?
53+ if ( tableInfo . Count != row . Row . Count )
4954 {
5055 LogError ( SqliteHelperResources . ErrorMoreElementsToAddThanRows ) ;
5156 return false ;
5257 }
5358
54- foreach ( var rows in row . Row )
59+ // Convert dictionary values to a list to access by index
60+ // (Assuming order matches Insert logic)
61+ var schemaColumns = tableInfo . Values . ToList ( ) ;
62+
63+ // Loop through each column in the row
64+ for ( int i = 0 ; i < row . Row . Count ; i ++ )
5565 {
56- if ( ! CheckNullability ( rows , convert ) )
66+ var value = row . Row [ i ] ;
67+ var definition = schemaColumns [ i ] ;
68+
69+ // Check Nullability
70+ if ( ! CheckNullability ( value , definition ) )
5771 {
5872 return false ;
5973 }
6074
61- if ( ! CheckTypeCompatibility ( rows , convert ) )
75+ // Check Data Type
76+ if ( ! CheckTypeCompatibility ( value , definition ) )
6277 {
6378 return false ;
6479 }
6580
66- if ( ! CheckUniqueness ( row , convert ) )
81+ // Check Uniqueness (Primary Key / Unique Constraint)
82+ if ( ! CheckBatchUniqueness ( value , i , definition , batch ) )
6783 {
6884 return false ;
6985 }
@@ -75,58 +91,68 @@ internal bool AdvancedSyntaxCheck(ICollection tableInfo, IEnumerable<TableSet> t
7591 /// <summary>
7692 /// Checks the nullability.
7793 /// </summary>
78- /// <param name="rows ">The rows .</param>
79- /// <param name="convert">The convert .</param>
94+ /// <param name="value ">The value to check .</param>
95+ /// <param name="convert">The column definition .</param>
8096 /// <returns>Condition fulfilled</returns>
81- private bool CheckNullability ( object rows , TableColumns convert )
97+ private bool CheckNullability ( string value , TableColumns convert )
8298 {
83- if ( rows != null || convert . NotNull )
99+ // Logic Fix: Valid if value exists OR if the column allows nulls (NOT NotNull).
100+ if ( ! string . IsNullOrEmpty ( value ) || ! convert . NotNull )
84101 {
85102 return true ;
86103 }
87104
88- LogError ( SqliteHelperResources . ErrorNotNullAble ) ;
105+ LogError ( $ " { SqliteHelperResources . ErrorNotNullAble } (Column: { convert . RowId } )" ) ;
89106 return false ;
90107 }
91108
92109 /// <summary>
93110 /// Checks the type compatibility.
94111 /// </summary>
95- /// <param name="rows ">The rows .</param>
96- /// <param name="convert">The convert .</param>
112+ /// <param name="value ">The value string .</param>
113+ /// <param name="convert">The column definition .</param>
97114 /// <returns>Condition fulfilled</returns>
98- private bool CheckTypeCompatibility ( string rows , TableColumns convert )
115+ private bool CheckTypeCompatibility ( string value , TableColumns convert )
99116 {
100- var check = SqliteProcessing . CheckConvert ( convert . DataType , rows ) ;
117+ // If empty and nullable, skip type check
118+ if ( string . IsNullOrEmpty ( value ) ) return true ;
119+
120+ var check = SqliteProcessing . CheckConvert ( convert . DataType , value ) ;
101121 if ( check )
102122 {
103123 return true ;
104124 }
105125
106- LogError ( $ "{ SqliteHelperResources . ErrorWrongType } - Value: { rows } , Expected Type: { convert . DataType } ") ;
126+ LogError ( $ "{ SqliteHelperResources . ErrorWrongType } - Value: { value } , Expected Type: { convert . DataType } ") ;
107127 return false ;
108128 }
109129
110130 /// <summary>
111- /// Checks the uniqueness.
131+ /// Checks the uniqueness within the current batch .
112132 /// </summary>
113- /// <param name="row">The row.</param>
114- /// <param name="convert">The convert.</param>
115- /// <returns></returns>
116- private bool CheckUniqueness ( TableSet row , TableColumns convert )
133+ /// <param name="value">The value to check.</param>
134+ /// <param name="columnIndex">Index of the column.</param>
135+ /// <param name="convert">The column definition.</param>
136+ /// <param name="batch">The full batch of rows.</param>
137+ /// <returns>True if unique in batch</returns>
138+ private bool CheckBatchUniqueness ( string value , int columnIndex , TableColumns convert , IEnumerable < TableSet > batch )
117139 {
140+ // Only check if it is a Primary Key or explicitly Unique
118141 if ( ! convert . PrimaryKey && ! convert . Unique )
119142 {
120143 return true ;
121144 }
122145
123- var isUnique = row . Row . Distinct ( ) . Count ( ) == row . Row . Count ;
124- if ( isUnique )
146+ // Check if this value appears more than once in this specific column index across the batch
147+ // Note: This does not check the Database itself, only the data we are about to insert.
148+ int count = batch . Count ( r => r . Row . Count > columnIndex && r . Row [ columnIndex ] == value ) ;
149+
150+ if ( count <= 1 )
125151 {
126152 return true ;
127153 }
128154
129- LogError ( SqliteHelperResources . ErrorNotUnique ) ;
155+ LogError ( $ " { SqliteHelperResources . ErrorNotUnique } (Duplicate found in batch: { value } )" ) ;
130156 return false ;
131157 }
132158
0 commit comments