Shane, I received your Beta 1 files, and have installed, read, and completed successfully an execute of all of the test scripts you provided:
General sample.scpt
Macscripter read.scpt
Macscripter write.scpt
Safari history.scpt
The documentation seems clear enough to me, and I’m doing some rich-text reformatting of it in an Evernote Note (mostly for my benefit now and future ref), which I’ll share very soon.
Thanks Shane. I don’t have time to look into this right now, but it’s definitely bookmarked for future use. There’s sql databases littered all over the mac that I need to access for security or forensics purposes. I normally do that with bash or python scripts, but having this option in AS could be handy.
One of my main uses for AppleScript is to provide simple click-and-go scripts for users to run diagnostic reports on their macs, so wrapping that f/w in a library would be useful, too.
Thanks for taking the time to do all that, @JMichaelTX .
One issue I’m looking for feedback from everyone on is the design. In particular, the decision to replace built-in methods that return boolean values for success or failure with methods that throw an AppleScript error on failure. I think this is more AppleScript style, although there’s a limitation that means all error with have the same number (-10000). Does this make sense to people?
Further, in the case of the update methods, I’ve added boolean versions as well. But I’m wondering if these are just an unnecessary complication. Thoughts?
Lastly, in the next version I’m going to add dedicated AS forms of the +databaseWith… methods. This is partly for consistency, but also for better error trapping. I’m also adding methods for loading a database into memory, and saving a database from memory to a file. My feeling is that that just about covers most bases. So is anything missing?
Note that you can also include a framework directly in a script bundle without a library. You just need to put it in a Frameworks folder inside the bundle’s Contents folder (not inside Resources).
Honestly, unlikely. It’s an extra level of overhead, and this is meant to be as fast as possible – and SQL stuff is not exactly for dabblers. It would also be a lot of work, and I’m not sure there’s wide enough appeal to warrant it.
That said, there’s nothing to stop someone else doing just that.
You going to have to convert to a list of lists, and then use executeUpdatesAS:withArguments:. But being able to pass CSV directly is an interesting idea…
I’m good with that. I would think that would cover most use cases.
I can see where this (read/write CSV/TSV files internally) could be extremely useful in migration (export/import) of large blocks of data between apps/databases.
Thanks for considering. BTW, if you need to, you can always delay this stuff to Ver 2.
I still have misgivings. I mean, it’s only saving two lines of code:
set {theString, theError} to current application's NSString's stringWithContentsOfFile:posixPath encoding:(current application's NSUTF8StringEncoding) |error|:(reference)
if theString is not missing value then error theError's localizedDescription() as text
and the tiniest amount of overhead. And there’s some sense in making sure that part of the process is working before even opening the database.
Interesting, when you use “overhead” that seems to suggest that a dictionary would slow it down, even when the dictionary commands are not being used. Is that correct?
Based on Beta 3 (2017-07-10) running Script Debugger 6.0.5 (6A205) on macOS 10.11.6.
To keep things simple and consistent, why not name TSV methods same as CSV methods:
--- USE THESE METHOD NAMES ---
theDb's executeUpdatesAS:"insert into test values (?, ?, ?, ?)" withTSV:tabbedText
theDb's executeUpdatesAS:"insert into test values (?, ?, ?, ?)" withTSVFromPath:(POSIX path of tempPath)
But then it occurred to me that maybe you don’t need separate methods for TSV and CSV data:
--- ACTUALLY, MAYBE YOU DON'T NEED BOTH METHODS. THIS WORKS ---
theDb's executeUpdatesAS:"insert into test values (?, ?, ?, ?)" ¬
withCSV:tabText commaIs:tab
--- BUT INSTEAD OF ---
withCSV: commaIs:
--- USE ---
withText: delim:
--- SO YOU'D HAVE ---
theDb's executeUpdatesAS:"insert into test values (?, ?, ?, ?)" ¬
withText:tabText delim:tab
I’d also prefer a simpler method for the “from path”:
theDb's executeUpdatesAS:"insert into test values (?, ?, ?, ?)" ¬
fromPath:(POSIX path of tempPath) delim:","
I did it the way I did because I see CSV as a recognized (pseudo) acronym, with TSV less so. But there’s something to be said for brevity, not to mention avoiding the whole issue of spelling separated .
That’s not going to work. The TSV stuff just breaks fields on tabs – there’s no way of including a tab within a field, for example. But CSV allows escaping of the delimiter, as well as allowing it in quoted fields – the process is more complex. So there has to be some way of knowing what’s wanted.
But there’s certainly value in being able to specify things like pipes and other characters, or even strings, as field delimiters.
FWIW, I’m after any more feedback on terminology. I was initially thinking of releasing it as a framework first and as a library later, but I’m now going to the library stage straight away. It won’t have defined terminology, but it will allow more simplified handler names.
For example, instead of using:
set theDb to current application's FMDatabase's databaseWithPathAS:posixPath
theDb's openWithFlagsAS:(current application's FMDBASOpenReadWriteCreate)
set theList to (theDb's executeQueryAS:"select * from test") as list
It will be like:
set theDb to theLib's makeNewDbWith:posixPath -- actually accepts file, alias, NSURL, or HFS/POSIX path
theDb's openReadWriteCreate()
set theList to (theDb's doQuery:"select * from test") as list
That notwithstanding, if anything in the existing terminology jars, now’s a good time to yell.
Because there are specific rules for CSV. You’ve seen one example: if a CSV field is completely within quotes, those quotes are treated as escaping quotes only, and are discarded.
You could use a tab as a delimiter in CSV – but that’s quite different from typical tab-delimited text, which is usually made by slicing first into paragraphs, and then dividing each paragraph on each tab, with no escaping allowed.
(Assuming you have a spreadsheet app, try doing some CSV and tab-delimited exports to see the difference.)