Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 22 additions & 13 deletions TablePro/Core/Services/SQL/SQLFolderWatcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -141,27 +141,17 @@ internal final class SQLFolderWatcher {
return
}

guard let enumerator = fileManager.enumerator(
at: folderURL,
includingPropertiesForKeys: [.isRegularFileKey, .contentModificationDateKey, .fileSizeKey],
options: [.skipsHiddenFiles]
) else {
return
}

var indexed: [LinkedSQLIndex.IndexedFile] = []

for case let url as URL in enumerator {
guard SQLFileService.supportedExtensions.contains(url.pathExtension.lowercased()) else { continue }

enumerateSQLFileURLs(in: folderURL, fileManager: fileManager) { url in
let resourceValues = try? url.resourceValues(forKeys: [
.isRegularFileKey, .contentModificationDateKey, .fileSizeKey
])
guard resourceValues?.isRegularFile == true else { continue }
guard resourceValues?.isRegularFile == true else { return }
let mtime = resourceValues?.contentModificationDate ?? Date()
let fileSize = Int64(resourceValues?.fileSize ?? 0)

guard let relativePath = relativePathFor(url: url, base: folderURL) else { continue }
guard let relativePath = relativePathFor(url: url, base: folderURL) else { return }
let header = FileTextLoader.loadHeader(url)
let metadata = header.map { SQLFrontmatter.parse($0.content) } ?? SQLFrontmatter.Metadata()
let encoding = header?.encoding ?? .utf8
Expand All @@ -184,6 +174,25 @@ internal final class SQLFolderWatcher {
await LinkedSQLIndex.shared.replaceAll(folderId: folder.id, files: indexed, folderURL: folderURL)
}

private static func enumerateSQLFileURLs(
in folderURL: URL,
fileManager: FileManager,
handle: (URL) -> Void
) {
guard let enumerator = fileManager.enumerator(
at: folderURL,
includingPropertiesForKeys: [.isRegularFileKey, .contentModificationDateKey, .fileSizeKey],
options: [.skipsHiddenFiles]
) else {
return
}

for case let url as URL in enumerator {
guard SQLFileService.supportedExtensions.contains(url.pathExtension.lowercased()) else { continue }
handle(url)
}
}

private static func pruneRemovedFolders(stillKnownIds: Set<UUID>) async {
let indexedIds = await LinkedSQLIndex.shared.allFolderIds()
let stale = indexedIds.subtracting(stillKnownIds)
Expand Down
6 changes: 5 additions & 1 deletion TablePro/ViewModels/WelcomeViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,11 @@ final class WelcomeViewModel {

// MARK: - Initialization

init(services: AppServices = .live) {
convenience init() {
self.init(services: .live)
}

init(services: AppServices) {
self.services = services
self.showOnboarding = !services.appSettingsStorage.hasCompletedOnboarding()
}
Expand Down
19 changes: 12 additions & 7 deletions TablePro/Views/Components/SQLReviewSheet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ struct SQLReviewSheet: View {
}

/// Past this many characters the display is truncated; the full text stays available via Copy All.
static let maxDisplayChars = 20_000
nonisolated static let maxDisplayChars = 20_000
/// Past this many characters tree-sitter is skipped in favour of a plain monospaced view.
static let treeSitterCutoff = 8_000
nonisolated static let treeSitterCutoff = 8_000

var body: some View {
VStack(spacing: 0) {
Expand Down Expand Up @@ -75,18 +75,23 @@ struct SQLReviewSheet: View {

private func prepare() async {
guard prepared == nil, !statements.isEmpty else { return }
let result = await Task.detached(priority: .userInitiated) { [statements, databaseType] in
Self.build(statements: statements, databaseType: databaseType)
let isJavaScript = PluginManager.shared.editorLanguage(for: databaseType) == .javascript
let result = await Task.detached(priority: .userInitiated) { [statements, isJavaScript] in
Self.build(statements: statements, isJavaScript: isJavaScript)
}.value
prepared = result
}

static func build(statements: [String], databaseType: DatabaseType) -> Prepared {
let isJS = PluginManager.shared.editorLanguage(for: databaseType) == .javascript
let isJavaScript = PluginManager.shared.editorLanguage(for: databaseType) == .javascript
return build(statements: statements, isJavaScript: isJavaScript)
}

private nonisolated static func build(statements: [String], isJavaScript: Bool) -> Prepared {
var full = statements
.map { $0.hasSuffix(";") ? $0 : $0 + ";" }
.joined(separator: "\n\n")
if isJS {
if isJavaScript {
full = convertExtendedJsonToShellSyntax(full)
}

Expand All @@ -112,7 +117,7 @@ struct SQLReviewSheet: View {
)
}

static func convertExtendedJsonToShellSyntax(_ mql: String) -> String {
nonisolated static func convertExtendedJsonToShellSyntax(_ mql: String) -> String {
let pattern = #"\{"\$oid":\s*"([0-9a-fA-F]{24})"\}"#
guard let regex = try? NSRegularExpression(pattern: pattern) else { return mql }
let nsString = mql as NSString
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,10 @@ struct ImportFromAppSourcePicker: View {
private func loadStates() {
Task.detached(priority: .userInitiated) {
let importers = ForeignAppImporterRegistry.all
var states: [(importer: any ForeignAppImporter, available: Bool, count: Int)] = []
for importer in importers {
let states: [(importer: any ForeignAppImporter, available: Bool, count: Int)] = importers.map { importer in
let available = importer.isAvailable()
let count = available ? importer.connectionCount() : 0
states.append((importer: importer, available: available, count: count))
return (importer: importer, available: available, count: count)
}
await MainActor.run {
importerStates = states
Expand Down
Loading