Skip to content

Commit 9a089da

Browse files
committed
wip
1 parent 3712dc3 commit 9a089da

3 files changed

Lines changed: 17 additions & 153 deletions

File tree

OpenTable.xcodeproj/project.pbxproj

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,8 @@
66
objectVersion = 77;
77
objects = {
88

9-
/* Begin PBXBuildFile section */
10-
5AAD97BC2F32E8D1003E05FC /* AUTOCOMPLETE_IMPROVEMENTS.md in Resources */ = {isa = PBXBuildFile; fileRef = 5AAD97BB2F32E8D1003E05FC /* AUTOCOMPLETE_IMPROVEMENTS.md */; };
11-
5AAD97BE2F32E8FD003E05FC /* SQLAutocompleteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AAD97BD2F32E8FD003E05FC /* SQLAutocompleteTests.swift */; };
12-
5AAD97C02F32E951003E05FC /* AUTOCOMPLETE_SUMMARY.md in Resources */ = {isa = PBXBuildFile; fileRef = 5AAD97BF2F32E951003E05FC /* AUTOCOMPLETE_SUMMARY.md */; };
13-
5AAD97C22F32E96E003E05FC /* QUICK_REFERENCE.md in Resources */ = {isa = PBXBuildFile; fileRef = 5AAD97C12F32E96E003E05FC /* QUICK_REFERENCE.md */; };
14-
/* End PBXBuildFile section */
15-
169
/* Begin PBXFileReference section */
1710
5A1091C72EF17EDC0055EA7C /* OpenTable.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OpenTable.app; sourceTree = BUILT_PRODUCTS_DIR; };
18-
5AAD97BB2F32E8D1003E05FC /* AUTOCOMPLETE_IMPROVEMENTS.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = AUTOCOMPLETE_IMPROVEMENTS.md; sourceTree = "<group>"; };
19-
5AAD97BD2F32E8FD003E05FC /* SQLAutocompleteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SQLAutocompleteTests.swift; sourceTree = "<group>"; };
20-
5AAD97BF2F32E951003E05FC /* AUTOCOMPLETE_SUMMARY.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = AUTOCOMPLETE_SUMMARY.md; sourceTree = "<group>"; };
21-
5AAD97C12F32E96E003E05FC /* QUICK_REFERENCE.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = QUICK_REFERENCE.md; sourceTree = "<group>"; };
2211
/* End PBXFileReference section */
2312

2413
/* Begin PBXFileSystemSynchronizedRootGroup section */
@@ -45,10 +34,6 @@
4534
children = (
4635
5A1091C92EF17EDC0055EA7C /* OpenTable */,
4736
5A1091C82EF17EDC0055EA7C /* Products */,
48-
5AAD97BB2F32E8D1003E05FC /* AUTOCOMPLETE_IMPROVEMENTS.md */,
49-
5AAD97BD2F32E8FD003E05FC /* SQLAutocompleteTests.swift */,
50-
5AAD97BF2F32E951003E05FC /* AUTOCOMPLETE_SUMMARY.md */,
51-
5AAD97C12F32E96E003E05FC /* QUICK_REFERENCE.md */,
5237
);
5338
sourceTree = "<group>";
5439
};
@@ -126,9 +111,6 @@
126111
isa = PBXResourcesBuildPhase;
127112
buildActionMask = 2147483647;
128113
files = (
129-
5AAD97C02F32E951003E05FC /* AUTOCOMPLETE_SUMMARY.md in Resources */,
130-
5AAD97C22F32E96E003E05FC /* QUICK_REFERENCE.md in Resources */,
131-
5AAD97BC2F32E8D1003E05FC /* AUTOCOMPLETE_IMPROVEMENTS.md in Resources */,
132114
);
133115
runOnlyForDeploymentPostprocessing = 0;
134116
};
@@ -139,7 +121,6 @@
139121
isa = PBXSourcesBuildPhase;
140122
buildActionMask = 2147483647;
141123
files = (
142-
5AAD97BE2F32E8FD003E05FC /* SQLAutocompleteTests.swift in Sources */,
143124
);
144125
runOnlyForDeploymentPostprocessing = 0;
145126
};
@@ -300,7 +281,7 @@
300281
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
301282
LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/Libs";
302283
MACOSX_DEPLOYMENT_TARGET = 15.0;
303-
MARKETING_VERSION = 0.1.22;
284+
MARKETING_VERSION = 0.1.23;
304285
"OTHER_LDFLAGS[arch=arm64]" = (
305286
"-force_load",
306287
"$(PROJECT_DIR)/Libs/libmariadb.a",
@@ -387,7 +368,7 @@
387368
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
388369
LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/Libs";
389370
MACOSX_DEPLOYMENT_TARGET = 15.0;
390-
MARKETING_VERSION = 0.1.22;
371+
MARKETING_VERSION = 0.1.23;
391372
"OTHER_LDFLAGS[arch=arm64]" = (
392373
"-force_load",
393374
"$(PROJECT_DIR)/Libs/libmariadb.a",

OpenTable/Core/Autocomplete/SQLCompletionProvider.swift

Lines changed: 1 addition & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -165,12 +165,10 @@ final class SQLCompletionProvider {
165165
])
166166

167167
case .alterTableColumn:
168-
// After ALTER TABLE tablename DROP/MODIFY/CHANGE/AFTER - suggest column names
168+
// After ALTER TABLE tablename DROP/MODIFY/CHANGE/RENAME or AFTER/BEFORE - suggest column names
169169
if let firstTable = context.tableReferences.first {
170170
items = await schemaProvider.columnCompletionItems(for: firstTable.tableName)
171171
}
172-
// Add positioning keywords
173-
items += filterKeywords(["COLUMN", "FIRST", "AFTER", "BEFORE"])
174172

175173
case .createTable:
176174
// Inside CREATE TABLE (...) - suggest constraints and data types
@@ -373,125 +371,4 @@ final class SQLCompletionProvider {
373371
}
374372
}
375373

376-
// MARK: - SQL Keywords Helper
377-
378-
/// Helper for common SQL keywords and functions
379-
enum SQLKeywords {
380-
/// Common SQL functions for autocomplete
381-
static func functionItems() -> [SQLCompletionItem] {
382-
let functions: [(name: String, signature: String?, doc: String?)] = [
383-
// Aggregate functions
384-
("COUNT", "COUNT(*)", "Counts rows"),
385-
("SUM", "SUM(column)", "Sums values"),
386-
("AVG", "AVG(column)", "Calculates average"),
387-
("MIN", "MIN(column)", "Finds minimum value"),
388-
("MAX", "MAX(column)", "Finds maximum value"),
389-
("GROUP_CONCAT", "GROUP_CONCAT(column)", "Concatenates values (MySQL)"),
390-
("STRING_AGG", "STRING_AGG(column, delimiter)", "Concatenates values (PostgreSQL)"),
391-
392-
// String functions
393-
("CONCAT", "CONCAT(str1, str2, ...)", "Concatenates strings"),
394-
("SUBSTRING", "SUBSTRING(str, start, length)", "Extracts substring"),
395-
("SUBSTR", "SUBSTR(str, start, length)", "Extracts substring"),
396-
("UPPER", "UPPER(str)", "Converts to uppercase"),
397-
("LOWER", "LOWER(str)", "Converts to lowercase"),
398-
("TRIM", "TRIM(str)", "Removes whitespace"),
399-
("LTRIM", "LTRIM(str)", "Removes left whitespace"),
400-
("RTRIM", "RTRIM(str)", "Removes right whitespace"),
401-
("LENGTH", "LENGTH(str)", "Returns string length"),
402-
("CHAR_LENGTH", "CHAR_LENGTH(str)", "Returns character length"),
403-
("REPLACE", "REPLACE(str, from, to)", "Replaces substring"),
404-
("LEFT", "LEFT(str, length)", "Returns leftmost characters"),
405-
("RIGHT", "RIGHT(str, length)", "Returns rightmost characters"),
406-
("REVERSE", "REVERSE(str)", "Reverses string"),
407-
408-
// Date/Time functions
409-
("NOW", "NOW()", "Returns current datetime"),
410-
("CURRENT_DATE", "CURRENT_DATE", "Returns current date"),
411-
("CURRENT_TIME", "CURRENT_TIME", "Returns current time"),
412-
("CURRENT_TIMESTAMP", "CURRENT_TIMESTAMP", "Returns current timestamp"),
413-
("DATE", "DATE(datetime)", "Extracts date part"),
414-
("TIME", "TIME(datetime)", "Extracts time part"),
415-
("YEAR", "YEAR(date)", "Extracts year"),
416-
("MONTH", "MONTH(date)", "Extracts month"),
417-
("DAY", "DAY(date)", "Extracts day"),
418-
("HOUR", "HOUR(datetime)", "Extracts hour"),
419-
("MINUTE", "MINUTE(datetime)", "Extracts minute"),
420-
("SECOND", "SECOND(datetime)", "Extracts second"),
421-
("DATE_FORMAT", "DATE_FORMAT(date, format)", "Formats date (MySQL)"),
422-
("TO_CHAR", "TO_CHAR(value, format)", "Formats value (PostgreSQL)"),
423-
("EXTRACT", "EXTRACT(field FROM source)", "Extracts date/time field"),
424-
("DATE_ADD", "DATE_ADD(date, INTERVAL value unit)", "Adds interval to date"),
425-
("DATE_SUB", "DATE_SUB(date, INTERVAL value unit)", "Subtracts interval from date"),
426-
("DATEDIFF", "DATEDIFF(date1, date2)", "Difference between dates"),
427-
("AGE", "AGE(timestamp)", "Calculate age (PostgreSQL)"),
428-
429-
// Mathematical functions
430-
("ABS", "ABS(number)", "Absolute value"),
431-
("ROUND", "ROUND(number, decimals)", "Rounds number"),
432-
("CEIL", "CEIL(number)", "Rounds up"),
433-
("CEILING", "CEILING(number)", "Rounds up"),
434-
("FLOOR", "FLOOR(number)", "Rounds down"),
435-
("MOD", "MOD(n, m)", "Modulo operation"),
436-
("POWER", "POWER(base, exponent)", "Raises to power"),
437-
("POW", "POW(base, exponent)", "Raises to power"),
438-
("SQRT", "SQRT(number)", "Square root"),
439-
("RAND", "RAND()", "Random number"),
440-
("RANDOM", "RANDOM()", "Random number (PostgreSQL)"),
441-
442-
// Conditional functions
443-
("COALESCE", "COALESCE(val1, val2, ...)", "Returns first non-null value"),
444-
("IFNULL", "IFNULL(value, alt)", "Returns alt if value is null (MySQL)"),
445-
("NULLIF", "NULLIF(val1, val2)", "Returns null if values equal"),
446-
("IF", "IF(condition, true_val, false_val)", "Conditional expression (MySQL)"),
447-
("CASE", "CASE WHEN ... THEN ... END", "Case expression"),
448-
449-
// Type conversion
450-
("CAST", "CAST(value AS type)", "Converts data type"),
451-
("CONVERT", "CONVERT(value, type)", "Converts data type"),
452-
453-
// JSON functions (MySQL 5.7+, PostgreSQL 9.2+)
454-
("JSON_EXTRACT", "JSON_EXTRACT(json, path)", "Extracts JSON value"),
455-
("JSON_OBJECT", "JSON_OBJECT(key, value, ...)", "Creates JSON object"),
456-
("JSON_ARRAY", "JSON_ARRAY(value, ...)", "Creates JSON array"),
457-
("JSONB_BUILD_OBJECT", "JSONB_BUILD_OBJECT(key, val, ...)", "Creates JSONB object (PostgreSQL)"),
458-
459-
// Window functions
460-
("ROW_NUMBER", "ROW_NUMBER() OVER(...)", "Assigns row number"),
461-
("RANK", "RANK() OVER(...)", "Assigns rank"),
462-
("DENSE_RANK", "DENSE_RANK() OVER(...)", "Assigns dense rank"),
463-
("LAG", "LAG(column, offset) OVER(...)", "Accesses previous row"),
464-
("LEAD", "LEAD(column, offset) OVER(...)", "Accesses next row"),
465-
]
466-
467-
return functions.map { name, signature, doc in
468-
SQLCompletionItem.function(name, signature: signature, documentation: doc)
469-
}
470-
}
471-
472-
/// SQL operators for autocomplete
473-
static func operatorItems() -> [SQLCompletionItem] {
474-
let operators: [(op: String, doc: String)] = [
475-
("=", "Equal to"),
476-
("<>", "Not equal to"),
477-
("!=", "Not equal to (alternative)"),
478-
(">", "Greater than"),
479-
("<", "Less than"),
480-
(">=", "Greater than or equal"),
481-
("<=", "Less than or equal"),
482-
("IS NULL", "Checks for NULL value"),
483-
("IS NOT NULL", "Checks for non-NULL value"),
484-
("LIKE", "Pattern matching"),
485-
("NOT LIKE", "Negated pattern matching"),
486-
("IN", "Value in list"),
487-
("NOT IN", "Value not in list"),
488-
("BETWEEN", "Value in range"),
489-
("NOT BETWEEN", "Value not in range"),
490-
]
491-
492-
return operators.map { op, doc in
493-
SQLCompletionItem.operator(op, documentation: doc)
494-
}
495-
}
496-
}
497374

OpenTable/Core/Autocomplete/SQLContextAnalyzer.swift

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,19 @@ final class SQLContextAnalyzer {
9696
private static let clauseRegexes: [(regex: NSRegularExpression, clause: SQLClauseType)] = {
9797
let patterns: [(String, SQLClauseType)] = [
9898
// DDL patterns (most specific first)
99-
// Match AFTER keyword specifically for column positioning
100-
("\\bAFTER\\s+[`\"']?\\w*[`\"']?\\s*$", .alterTableColumn),
101-
("\\bFIRST\\s*$", .alterTableColumn),
99+
// Match AFTER/BEFORE keyword in ALTER TABLE ADD COLUMN context
100+
("\\bADD\\s+(?:COLUMN\\s+)?[`\"']?\\w+[`\"']?\\s+\\w+.*?\\b(?:AFTER|BEFORE)(?:\\s+\\w*)?$", .alterTableColumn),
101+
// Match AFTER/BEFORE in general ALTER TABLE context
102+
("\\b(?:AFTER|BEFORE)(?:\\s+\\w*)?$", .alterTableColumn),
103+
// Match FIRST keyword for column positioning
104+
("\\bFIRST\\s*$", .alterTable),
105+
// Match ADD keyword immediately after ALTER TABLE tablename (expecting COLUMN, INDEX, etc.)
106+
("\\bALTER\\s+TABLE\\s+[`\"']?\\w+[`\"']?\\s+ADD\\s+\\w*$", .alterTable),
102107
// Match column definition after ADD/MODIFY/CHANGE with data type
103-
("\\b(?:ADD|MODIFY|CHANGE)\\s+(?:COLUMN\\s+)?[`\"']?\\w+[`\"']?\\s+\\w+(?:\\([^)]*\\))?(?:\\s+(?:NOT\\s+)?NULL|\\s+DEFAULT|\\s+AUTO_INCREMENT|\\s+UNSIGNED|\\s+COMMENT)?\\s+\\w*$", .columnDef),
104-
// Match column name after ADD/MODIFY/CHANGE (before data type)
105-
("\\b(?:ADD|MODIFY|CHANGE)\\s+(?:COLUMN\\s+)?\\w+\\s*$", .columnDef),
108+
("\\b(?:ADD|MODIFY|CHANGE)\\s+(?:COLUMN\\s+)?[`\"']?\\w+[`\"']?\\s+\\w+(?:\\([^)]*\\))?(?:\\s+(?:NOT\\s+)?NULL|\\s+DEFAULT(?:\\s+[^\\s]+)?|\\s+AUTO_INCREMENT|\\s+UNSIGNED|\\s+COMMENT(?:\\s+'[^']*')?)*\\s*$", .columnDef),
109+
// Match column name after ADD/MODIFY/CHANGE (before data type)
110+
// Only match if we have COLUMN keyword or it's after ALTER TABLE
111+
("\\b(?:ADD|MODIFY|CHANGE)\\s+COLUMN\\s+\\w+\\s*$", .columnDef),
106112
// Match DROP/MODIFY/CHANGE/RENAME with column name
107113
("\\bALTER\\s+TABLE\\s+[`\"']?\\w+[`\"']?\\s+(?:DROP|MODIFY|CHANGE|RENAME)\\s+(?:COLUMN\\s+)?[`\"']?\\w*[`\"']?\\s*$", .alterTableColumn),
108114
// General ALTER TABLE operations
@@ -610,8 +616,8 @@ final class SQLContextAnalyzer {
610616

611617
/// Pre-compiled regex for extracting table name from ALTER TABLE statements
612618
private static let alterTableRegex: NSRegularExpression? = {
613-
// Pattern: ALTER TABLE tablename (supports optional quoting and special characters)
614-
let pattern = "(?i)\\bALTER\\s+TABLE\\s+[`\"']?([^`\"']+)[`\"']?"
619+
// Pattern: ALTER TABLE tablename (supports optional quoting)
620+
let pattern = "(?i)\\bALTER\\s+TABLE\\s+[`\"']?(\\w+)[`\"']?"
615621
return try? NSRegularExpression(pattern: pattern)
616622
}()
617623

0 commit comments

Comments
 (0)