jhass changed the topic of #crystal-lang to: The Crystal programming language | http://crystal-lang.org | Crystal 0.28.0 | Fund Crystal's development: http://is.gd/X7PRtI | GH: https://github.com/crystal-lang/crystal | Docs: http://crystal-lang.org/docs/ | API: http://crystal-lang.org/api/ | Gitter: https://gitter.im/crystal-lang/crystal
<FromGitter> <nsuchy> 300
<FromGitter> <nsuchy> Not 30
<FromGitter> <nsuchy> It’s a data feed and the production feed is several GB
<FromGitter> <nsuchy> I want to optimize well as possible before I switch from the Node.js processor to the Crystal processor
<FromGitter> <nsuchy> It’s my understanding SQLite was also a bottleneck, not sure how faster the Crystal library is compared to Node.js
laaron has quit [Quit: ZNC 1.7.1 - https://znc.in]
laaron has joined #crystal-lang
<FromGitter> <Blacksmoke16> depending on what you're doing, prob a lot
<FromGitter> <nsuchy> a lot of inserts
<FromGitter> <nsuchy> like a lot
<FromGitter> <Blacksmoke16> could prob make the inserts in a single query
<FromGitter> <nsuchy> Parsing huge JSON feeds (several GB of data) and caching into SQLite for internal use
<FromGitter> <Blacksmoke16> gotcha
<FromGitter> <nsuchy> how do I build as release
<FromGitter> <nsuchy> typing --release gets an LLVM error
<FromGitter> <Blacksmoke16> `crystal build --release my_app.cr`
<FromGitter> <Blacksmoke16> oh?
<FromGitter> <nsuchy> using with run though
<FromGitter> <nsuchy> not build
<FromGitter> <Blacksmoke16> easiest to just use build
<FromGitter> <nsuchy> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ce9e4039404bf2aedad16b9]
<FromGitter> <nsuchy> using build
<FromGitter> <Blacksmoke16> how did you install crystal
<FromGitter> <nsuchy> asdf
<FromGitter> <nsuchy> it's a version manager tool
<FromGitter> <Blacksmoke16> yea something prob didnt get installed right
<FromGitter> <Blacksmoke16> :shrug:
<FromGitter> <Blacksmoke16> cant say i ever saw that error before
<FromGitter> <nsuchy> Nathaniels-MacBook-Pro% crystal --version ⏎ Crystal 0.28.0 (2019-04-17) ⏎ ⏎ LLVM: 3.9.1 ⏎ Default target: x86_64-apple-macosx [https://gitter.im/crystal-lang/crystal?at=5ce9e46f9404bf2aedad1984]
<FromGitter> <Blacksmoke16> maybe try with llvm 4.0.0
<FromGitter> <nsuchy> I don't have any way to change the version
<FromGitter> <Blacksmoke16> asdf is using an older version of llvm i guess
<FromGitter> <Blacksmoke16> vs brew?
<FromGitter> <Blacksmoke16> yea upgrading llvm seems to be the solution as far as i can tell
<FromGitter> <nsuchy> hmm okay
<FromGitter> <nsuchy> I'll uninstall the asdf version
<FromGitter> <nsuchy> I have little incentive to use older versions anyways
<FromGitter> <nsuchy> its not like ruby where certain packages require old ruby versions
<FromGitter> <nsuchy> yeah so homebrew has llvm 6
<FromGitter> <Blacksmoke16> 👍
<FromGitter> <nsuchy> weird though asdf is using such an old version
<FromGitter> <nsuchy> probably to support older crystal versions
<FromGitter> <Blacksmoke16> :shrug:
<FromGitter> <tenebrousedge> @Blacksmoke16 are you on OSX?
<FromGitter> <Blacksmoke16> my work laptop is yes
<FromGitter> <Blacksmoke16> but desktop at home is debian
<FromGitter> <nsuchy> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ce9e6c78f019114aeb88216]
<FromGitter> <nsuchy> Wow
<FromGitter> <Blacksmoke16> 👍
<FromGitter> <nsuchy> 6 seconds
<FromGitter> <Blacksmoke16> looks about right
<FromGitter> <nsuchy> wow
<FromGitter> <Blacksmoke16> remind me of that guy that moved his ruby code over and went from 9min 13 sec to 1min 54 sec
<FromGitter> <Blacksmoke16> then did release mode and went down to 18s
<FromGitter> <tenebrousedge> yeah that's kinda what I love about this language. I mean, Ruby is a dream, but Crystal is bottled lightning
<FromGitter> <nsuchy> yes like
<FromGitter> <nsuchy> now I just need to write the database insert logic
<FromGitter> <nsuchy> and I can have a full picture to benchmark
<FromGitter> <nsuchy> anything else I can do to speed up the parsing?
<FromGitter> <nsuchy> 6 seconds is great
<FromGitter> <nsuchy> would anything shave off time?
<FromGitter> <Blacksmoke16> reminds me a project i did, ruby to crystal
<FromGitter> <nsuchy> It uses JSON.mapping() and a lot of subclasses
<FromGitter> <Blacksmoke16> structs
<FromGitter> <Blacksmoke16> went from 22 sec to 20ms
<FromGitter> <Blacksmoke16> but im going to give most of that credit to less shitty code
<FromGitter> <Blacksmoke16> :s
<FromGitter> <nsuchy> Wait really?
<FromGitter> <nsuchy> I'm willing to listen
<FromGitter> <Blacksmoke16> of what? my project or structs?
<FromGitter> <nsuchy> Of structs
<FromGitter> <Blacksmoke16> yea just replace class with struct
<FromGitter> <Blacksmoke16> and try again
<FromGitter> <Blacksmoke16> imma take a guess and say 3 sec
<FromGitter> <Blacksmoke16> no i mean like
<FromGitter> <nsuchy> what do structs look like?
<FromGitter> <Blacksmoke16> `class MyClass`
<FromGitter> <Blacksmoke16> `struct MyClass`
<FromGitter> <Blacksmoke16> ^
<FromGitter> <nsuchy> is there any code changes needed
<FromGitter> <Blacksmoke16> no
<FromGitter> <nsuchy> other than change class to struct
<FromGitter> <Blacksmoke16> prob not if all you're doing is reading in data from josn
<FromGitter> <Blacksmoke16> imma drop down to 500ms guess
<FromGitter> <Blacksmoke16> should be a noticeable improvement
<FromGitter> <nsuchy> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ce9e97becdf942b4c4759af]
<FromGitter> <nsuchy> :(
<FromGitter> <nsuchy> The structs are inside a module if that makes a difference
<FromGitter> <Blacksmoke16> all the time must be in the parsing of the JSON itself
<FromGitter> <Blacksmoke16> it shouldnt
<FromGitter> <tenebrousedge> the JSON is being written to SQLite after this?
<FromGitter> <Blacksmoke16> i think he's just doing a from_json on the big file
<FromGitter> <nsuchy> not yet
<FromGitter> <nsuchy> Just using Struct name .from_json
<FromGitter> <Blacksmoke16> yea id imagine most of the time there is spent on parsing/reading json?
<FromGitter> <Blacksmoke16> vs newing up structs/classes
<FromGitter> <nsuchy> :|
laaron has quit [Remote host closed the connection]
<FromGitter> <tenebrousedge> but that could be parallelized probably, and if there's no intermediate transformation that needs to happen to the strings, you could maybe use some low-level construct instead of `String`
laaron has joined #crystal-lang
<FromGitter> <Blacksmoke16> Would fibers help read the file faster?
<FromGitter> <nsuchy> How would I go about that?
<FromGitter> <Blacksmoke16> IDK
<FromGitter> <nsuchy> For example, `@vectorString="CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N",` the value needs to get copied into SQLite that's it
griddle has joined #crystal-lang
<FromGitter> <nsuchy> Big inserts would also be nice
<FromGitter> <nsuchy> If I could pop off say 20 items from an array and insert them into the correct table and then go to the next 20 items
<FromGitter> <Blacksmoke16> Probably pretty easy
<FromGitter> <tenebrousedge> parallelizing the read on the other hand would probably be more trouble than it's worth
<FromGitter> <nsuchy> @tenebrousedge the feeds I am parsing are in multitudes of GB
laaron has quit [Quit: ZNC 1.7.1 - https://znc.in]
<FromGitter> <nsuchy> I'm willing to try anything
<FromGitter> <tenebrousedge> I would write an iterator that would take n lines at a time, and then pass those to different fibers for processing/insertion
<FromGitter> <nsuchy> Can I do that with file.open?
<FromGitter> <nsuchy> For example `myobject = Entity.from_json(File.open("./src/example-json-files/2018.json"))`
<FromGitter> <Blacksmoke16> Try doing file.read instead
laaron has joined #crystal-lang
<FromGitter> <Blacksmoke16> Probably won't make much of a difference tho
<FromGitter> <nsuchy> Not true
<FromGitter> <nsuchy> huge difference
<FromGitter> <nsuchy> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ce9ed2a9404bf2aedad4661]
<FromGitter> <tenebrousedge> 👀
<FromGitter> <Blacksmoke16> Nice
<FromGitter> <nsuchy> So use File.read instead of File.open
<FromGitter> <Blacksmoke16> well depends on what you want
<FromGitter> <nsuchy> just need READ access
<FromGitter> <nsuchy> Reproducible ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ce9ed8b879f4478c7e18ce5]
<FromGitter> <Blacksmoke16> yea file.read just opens it in read mode, copys the IO to a string and returns the string
<FromGitter> <nsuchy> I have to do this times multiple GB
<FromGitter> <nsuchy> willing to go a lot of effort to save on processing time
laaron has quit [Remote host closed the connection]
<FromGitter> <Blacksmoke16> hmm
<FromGitter> <Blacksmoke16> well at this point im out of ideas
laaron has joined #crystal-lang
<FromGitter> <nsuchy> `File.read()` is amazing in itsel
<FromGitter> <Blacksmoke16> what happens if you did like `File.read("path", encoding: "UTF-8")`
<FromGitter> <nsuchy> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ce9eecdb313d723142c20bb]
<FromGitter> <Blacksmoke16> i figured
<FromGitter> <nsuchy> yeah :\
<FromGitter> <Blacksmoke16> prob best you going to get less you have another idea
<FromGitter> <nsuchy> yeah
<FromGitter> <nsuchy> :|
laaron has quit [Remote host closed the connection]
laaron has joined #crystal-lang
<FromGitter> <Blacksmoke16> refactored how i handle env specific config
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ce9f23fecdf942b4c478bc2]
<FromGitter> <Blacksmoke16> is all in one file now, can define custom settings for each env, including custom envs. is based off of env var
<FromGitter> <Blacksmoke16> also determines the default behavior for the logger
<FromGitter> <Blacksmoke16> STDOUT and file if on dev, none on testing, and file if its >= warning on prod
<FromGitter> <watzon> Ok this is extremely basic so I don't know why it doesn't work. Why is it that including a module does't add its methods as class methods, and is there a way to do so? https://carc.in/#/r/6zac
<FromGitter> <watzon> That's pretty cool @Blacksmoke16
<FromGitter> <Blacksmoke16> use `extend` instead of `include`
<FromGitter> <watzon> https://carc.in/#/r/6zag
<FromGitter> <watzon> Then it breaks the class variables
<FromGitter> <Blacksmoke16> huh
<FromGitter> <Blacksmoke16> dunno
<FromGitter> <Blacksmoke16> and thanks :)
<FromGitter> <Blacksmoke16> it's getting there
<FromGitter> <watzon> Sure is :)
<FromGitter> <watzon> I don't know if this is a bug or expected behavior. I'm going to assume the latter, but I find it very unintuitive coming from how Ruby does it.
<FromGitter> <watzon> The only thing that I've found that works is to do all instance variable declarations in a `macro included` and then include the module, but that ruins the whole purpose of the module since the instance vars get declared in the class that's doing the including instead of the module.
<FromGitter> <Blacksmoke16> dunno
<FromGitter> <Blacksmoke16> anyway im off to bed o/
<FromGitter> <watzon> Well good night!
laaron has quit [Remote host closed the connection]
laaron has joined #crystal-lang
laaron has quit [Quit: ZNC 1.7.1 - https://znc.in]
laaron has joined #crystal-lang
laaron has quit [Quit: ZNC 1.7.1 - https://znc.in]
laaron has joined #crystal-lang
laaron has quit [Quit: ZNC 1.7.1 - https://znc.in]
laaron has joined #crystal-lang
<FromGitter> <yorci> can anyone explain me why when pass variable with parantheses to macro variable which is passed, it yields passed variable name instead of variable content? ⏎ ⏎ https://carc.in/#/r/6zdj
<FromGitter> <yorci> or i must ask how can i invoke method which is passed as variable to macro ?
<FromGitter> <watzon> @yorci because the value of your variable is not known at compile time
<FromGitter> <watzon> macros are expanded at compile time
<FromGitter> <yorci> i see, i must pass the method name directly right?
<FromGitter> <tenebrousedge> @yorci https://carc.in/#/r/6ze3
<FromGitter> <watzon> Yes
<FromGitter> <watzon> Either that or I think you can use a constant
<FromGitter> <tenebrousedge> not like that. I tried it o_o
<FromGitter> <tenebrousedge> there is also `method_missing`
<FromGitter> <yorci> these are not fullfil my needs, i am trying to make something like event register and fire macro, registering is okay, its registering in my program files but event fire is problematic, i get data from api, its a hash variable which is contains method name and arguments, so i need to invoke method by that method name in hash, i mean i think that way is more flexible and modular.
<FromGitter> <yorci> but if icant do that dynamicly, i need to use a switch case i think
<FromGitter> <tenebrousedge> well, why not just use a hash where the values are `Proc`s?
<FromGitter> <yorci> what you mean
<FromGitter> <yorci> hash is actually a json object
<FromGitter> <yorci> {"command": "method1", "args": ["t1","t2","t3"]} ⏎ ⏎ such as
<FromGitter> <tenebrousedge> https://carc.in/#/r/6ze7
<FromGitter> <watzon> As @tenebrousedge said, use procs
<FromGitter> <yorci> hmm you mean nevermind about macros, just create a hash of procs and register method as proc, fire that method by proc.call, am i understand right?
<FromGitter> <tenebrousedge> I mean, if you have a good reason not to, it seems like an easy solution
<FromGitter> <tenebrousedge> you may want to define a `default_block` on your hash for any missing keys
<FromGitter> <yorci> it looks pretty mess but modular 😃 thank you, i think i will make this way.
<FromGitter> <watzon> You can use a method to register an event like this
<FromGitter> <watzon> Obviously you probably want to do a little bit more there, but that's the basic idea
<FromGitter> <yorci> yes actually i was tried procs first but procs needs to static argument size & type and return type, so i change it to define method and invoke it by macro. ⏎ ⏎ its hard to seperate logics compile time / run time for me as an long term interpreter developer 😃 , i've never write code flexible as much as i want 😃
<FromGitter> <watzon> Crystal needs more hash functions, ie native sha2/3
<FromGitter> <watzon> Or at the very least better documentation around them, because I can't find SHA-256 and SHA-512
laaron has quit [Quit: ZNC 1.7.1 - https://znc.in]
laaron has joined #crystal-lang
<FromGitter> <watzon> Figured it out. OpenSSL::Digest needs some docs
laaron has quit [Quit: ZNC 1.7.1 - https://znc.in]
laaron has joined #crystal-lang
<FromGitter> <r00ster91> I'm trying to run a Crystal executable on a Raspberry Pi. I tried to cross compile with the target `aarch64-linux-gnu` and with `aarch64-linux-musl` and then run the `cc` command on the Raspberry Pi but both .o files fail with ` file not recognized: File format not recognized`
ShalokShalom has joined #crystal-lang
ShalokShalom62 has joined #crystal-lang
ShalokShalom62 has quit [Remote host closed the connection]
<FromGitter> <r00ster91> oh the correct target seems to be `arm-unknown-linux-gnueabihf `
ashirase has quit [Ping timeout: 258 seconds]
ashirase has joined #crystal-lang
DTZUZU has quit [Ping timeout: 248 seconds]
laaron has quit [Quit: ZNC 1.7.1 - https://znc.in]
laaron has joined #crystal-lang
_whitelogger has joined #crystal-lang
_whitelogger has joined #crystal-lang
ShalokShalom has quit [Remote host closed the connection]
DTZUZU has joined #crystal-lang
<FromGitter> <alex-lairan> Hello ! ⏎ ⏎ I have a JSON like `"[{\"text\":\"Should I go ?\",\"responses\":[\"yes\",\"no\"]}]"` ⏎ ⏎ To read the JSON, I created a ... [https://gitter.im/crystal-lang/crystal?at=5cea9811879f4478c7e5a461]
<FromGitter> <Blacksmoke16> Array(QuestionLoader).from_json(params[:questions])`
<FromGitter> <Blacksmoke16> its an array of that type, not just a single obj of that type
<FromGitter> <alex-lairan> Yes, thanks ! ⏎ ⏎ I've forget the Array :D
<FromGitter> <Blacksmoke16> np
_whitelogger has joined #crystal-lang
<FromGitter> <Blacksmoke16> is there not a way to generate `<<: *development` using yaml nodes builder?
<FromGitter> <Blacksmoke16> seems to be missing
laaron has quit [Remote host closed the connection]
laaron has joined #crystal-lang
<FromGitter> <Blacksmoke16> `All "emitting" methods support specifying a "reference" object that will be associated to the emitted object, so that when that reference object is emitted again an anchor and an alias will be created. This generates both more compact documents and allows handling recursive data structures.`
<FromGitter> <Blacksmoke16> sounds like using reference does that
laaron has quit [Remote host closed the connection]
laaron has joined #crystal-lang
<FromGitter> <dscottboggs_gitlab> https://carc.in/#/r/6zg5 ⏎ ⏎ :D phew I'm really glad that works
<FromGitter> <tenebrousedge> why would it not?
<FromGitter> <dscottboggs_gitlab> > I've forget the Array :D ⏎ ⏎ I've definitely done that :D
<FromGitter> <dscottboggs_gitlab> > why would it not? ⏎ ⏎ not every language likes to do overloads, and since macros are more dynamic I wasn't sure if they would work right or just overwrite the previous one
<FromGitter> <tenebrousedge> ahhhhh
<FromGitter> <tenebrousedge> thanks for explaining
<FromGitter> <dscottboggs_gitlab> I could've gotten an error saying that `test "arg1"` was not a valid call because it was expecting `test` to take 2 args. that would've been real annoying :p
<FromGitter> <dscottboggs_gitlab> np :)
<FromGitter> <Blacksmoke16> ayy i figured it out
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ceaa9a5b313d7231430d5cc]
<FromGitter> <Blacksmoke16> kinda annoying but ill take it
<FromGitter> <j8r> @r00ster91 you can also try https://gist.github.com/j8r/34f1a344336901960c787517b5b6d616
<FromGitter> <dscottboggs_gitlab> @Blacksmoke16 interesting
<FromGitter> <Blacksmoke16> generates ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ceab30a879f4478c7e656cc]
<FromGitter> <Blacksmoke16> @dscottboggs_gitlab ^
<FromGitter> <Blacksmoke16> er i added the anchors to test/prod, but yea
<FromGitter> <dscottboggs_gitlab> that's really interesting... I wish YAML wasn't so complicated to deal with :/
<FromGitter> <j8r> yes, YAML can be confusing at times for humans, and is not simple to parse for machines
<FromGitter> <Blacksmoke16> much cleaner than the JSON version of this would be tho
<FromGitter> <Blacksmoke16> as i dont think you could extend other objects in json
<FromGitter> <Blacksmoke16> would have have to duplicate the whole obj for each env, instead of just changing what you want
<FromGitter> <dscottboggs_gitlab> or have that be a separate thing
<FromGitter> <Blacksmoke16> like separate files?
<FromGitter> <dscottboggs_gitlab> Like you could have a configurations section, then have a like `{"development": ["conf1", "conf2"] }`, then like `{"production": ["conf1", "conf3", "conf4"]}` which would each be merged together
<FromGitter> <Blacksmoke16> true
<FromGitter> <j8r> the logic has to be done ourselves
<FromGitter> <Blacksmoke16> yea, vs that yaml code works with like from_yaml
laaron has quit [Remote host closed the connection]
laaron has joined #crystal-lang
Vexatos has quit [Ping timeout: 258 seconds]
RX14 has quit [Ping timeout: 252 seconds]
<FromGitter> <nsuchy> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ceac136879f4478c7e6bbb2]
<FromGitter> <nsuchy> I get a nil error for this code
<FromGitter> <nsuchy> even though I check ahead of time if its false
<FromGitter> <j8r> nil you mean?
<FromGitter> <nsuchy> yes
<FromGitter> <nsuchy> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ceac1b2ecdf942b4c4ca4fc]
<FromGitter> <nsuchy> even though I check ahead of time
<FromGitter> <nsuchy> If you saw I checked unless false
<FromGitter> <j8r> assign to a var, `if cve_items = myobject.cve_items`
<FromGitter> <j8r> you can also do `myobject.cve_items.try &.each do |item| ...`
<FromGitter> <tenebrousedge> `each` with an empty set should be a no-op anyway
<FromGitter> <nsuchy> that's bad behavior having to assign in the check
<FromGitter> <nsuchy> think this counts as a bug?
<FromGitter> <tenebrousedge> no
<FromGitter> <nsuchy> explain why not?
<FromGitter> <nsuchy> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ceac2a8d22ba766a2031ee9]
<FromGitter> <nsuchy> Works
<FromGitter> <nsuchy> if myobject ⏎ ⏎ ```code paste, see link``` ⏎ ⏎ end [https://gitter.im/crystal-lang/crystal?at=5ceac2b6879f4478c7e6c5bc]
<FromGitter> <nsuchy> fails
<FromGitter> <j8r> https://crystal-lang.org/reference/syntax_and_semantics/if_var.html#limitations ⏎ ⏎ > The above logic doesn’t work with instance variables, class variables and variables bound in a closure. The value of these kinds of variables could potentially be affected by another fiber after the condition was checked, rendering it nil.
<FromGitter> <tenebrousedge> that the variable could be `nil` at runtime is not a bug, neither is aggressively checking for that. It's somewhat annoying, but it prevents problems
<FromGitter> <nsuchy> interesting so because it's an instance of a class it can randomly become nil?
<FromGitter> <j8r> if you want, yes
<jhass> not randomly, but at any point given concurrent writes to it
<FromGitter> <j8r> spawning fibers can change its value
<FromGitter> <nsuchy> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ceac38e8f019114aebdfa89]
<FromGitter> <nsuchy> this gets messy fast
<jhass> to be clear fibers that write to it, not any fibers
<FromGitter> <j8r> you can use `try` @nsuchy
<FromGitter> <nsuchy> what happens if try fails?
<jhass> pp format if format = item.try(&.cve).try(&.data_format)
<FromGitter> <nsuchy> do I get a runtime error
<FromGitter> <j8r> try `try`
<jhass> try returns nil if the receiver is nil, .not_nil! raises a runtime error
<FromGitter> <tenebrousedge> @nsuchy also check out `dig` https://crystal-lang.org/api/0.28.0/JSON/Any.html#dig%28key%3AString%7CInt%2C%2Asubkeys%29-instance-method
ShalokShalom has joined #crystal-lang
<FromGitter> <nsuchy> it's mapped to an object now
Vexatos has joined #crystal-lang
<jhass> you don't need to make your mapping nilable if the fields are not optional to you. You'll get a runtime error at parse time then if the assumption doesn't hold
<FromGitter> <tenebrousedge> If the mapped object does not provide `dig`, it's relatively easy to add: ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ceac53163dea422b4ec5775]
<FromGitter> <nsuchy> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ceac5adef853135c828ed88]
<FromGitter> <nsuchy> this while a bit difficult to read is shorter
<FromGitter> <nsuchy> and less nested if hell
ShalokShalom has quit [Remote host closed the connection]
<FromGitter> <j8r> what's the problem you want to solve?
<jhass> actually you can do item.cve.try(&.data_type) given item can't be nil
ShalokShalom has joined #crystal-lang
<FromGitter> <nsuchy> @j8r I've mapped a huge json file to an object and I need to access keys efficiently and insert them into an SQLite Database
<FromGitter> <j8r> so, validate the schema first, so you won't have any `nil` (unless you want)
RX14 has joined #crystal-lang
<FromGitter> <j8r> with `JSON::Serializable` or `JSON.mapping`
<FromGitter> <nsuchy> Wel that's the issue
<FromGitter> <nsuchy> not all entries have a specific key
<FromGitter> <nsuchy> so they need to be nilable
<FromGitter> <j8r> ok, you don't have much choice to check it at runtime then
<FromGitter> <nsuchy> yeah
<FromGitter> <j8r> it's quite readable to do `maybe_nil.try &.each` instead of `never_nil.each`
<FromGitter> <j8r> IMHO
<jhass> I also like to do things like next unless item.something inside loops which only access one field of the iterated item type
<FromGitter> <nsuchy> ```data_type = item.try(&.cve).try(&.data_type) || "Not available"```
<FromGitter> <nsuchy> Would this switch to "Not available" if nil is returned
<jhass> sure
<FromGitter> <nsuchy> I'm gonna pass data_type to SQLite
<FromGitter> <nsuchy> so that would be readable enough for me
<FromGitter> <Blacksmoke16> should the columns in the db be null if that property wasnt in the json? or is there some default value
<FromGitter> <nsuchy> it serves as a helpful error message
<FromGitter> <nsuchy> the other project devs don't like null data
<jhass> take care you don't just invent your own null type here though
<FromGitter> <Blacksmoke16> ^
<jhass> that's easily worse then having nulls
<FromGitter> <nsuchy> I'll discuss with them
<FromGitter> <nsuchy> for now though
<FromGitter> <nsuchy> default string provided by Crystal is necessary
<FromGitter> <nsuchy> I can always improve the code later
<FromGitter> <nsuchy> :D
<FromGitter> <Blacksmoke16> if there are valid defaults for stuff you can define those in your mapping so if a property is missing it gets that value
<FromGitter> <Blacksmoke16> also could be used for arrays, set it to empty array if not there etc
<FromGitter> <Blacksmoke16> but i wouldnt just give defaults for sake of skipping nil checks
<FromGitter> <nsuchy> it's more about, other developers, on 100s of projects written in different languages, not doing nil checks
<FromGitter> <nsuchy> :P
<jhass> basically if any code ever has to do something == "Not available" anywhere, you're doing it wrong
<FromGitter> <Blacksmoke16> ^
<FromGitter> <nsuchy> Even if my project was 100% nil-safe, every other project would have to to be okay with null values in SQLite
<FromGitter> <Blacksmoke16> sounds like they got into a bad habit
<FromGitter> <Blacksmoke16> null is a totally valid value
<FromGitter> <nsuchy> yes
<FromGitter> <nsuchy> I agree
<FromGitter> <nsuchy> Although I'm one noob programmer who got lucky enough to find out about crystal
<FromGitter> <nsuchy> Can't exactly rewrite the rest of the company's software even if I wanted to
<FromGitter> <Blacksmoke16> fair enough
<FromGitter> <tenebrousedge> a perfect world wouldn't need `NULL`, I think. But it's at least theoretically possible that this is not the best of all possible worlds
<FromGitter> <Blacksmoke16> well it has its uses
<FromGitter> <Blacksmoke16> like a record that hasnt been deleted yet with a deleted_at column
<jhass> an alternative could be not inserting those rows and generate a report about not inserted items at the end of the report. If it's really just about noticing that
<FromGitter> <nsuchy> @Blacksmoke16 Fun fact, most data is never deleted, it's retained for legal reasons and users are lied to about it being deleted xD
<FromGitter> <Blacksmoke16> thats the point of the deleted_at column
<FromGitter> <nsuchy> `is_deleted = true`
<FromGitter> <nsuchy> ;)
<FromGitter> <nsuchy> totally gone
<FromGitter> <Blacksmoke16> lets you know when a row was deleted w/o actually deleting it
<FromGitter> <Blacksmoke16> deleted_at would be better imo
<FromGitter> <nsuchy> except when legal comes knocking
<jhass> "for legal reasons" is funny in GDPR times :P
<FromGitter> <Blacksmoke16> as you inherently get *when* it was deleted as well
<FromGitter> <nsuchy> jhass: Very true, the bureaucracy demands fake deletes though for legal dept
<FromGitter> <nsuchy> @Blacksmoke16 will pass that idea to the project team
<FromGitter> <Blacksmoke16> 👍 same idea with created_at and updated_at
<FromGitter> <j8r> Not only Facebook do that? what a surprise
<FromGitter> <Blacksmoke16> soft deleting is also useful for reporting
<FromGitter> <Blacksmoke16> as you're able to retain the relations between records
<FromGitter> <tenebrousedge> theoretically the record with the `deleted_at DEFAULT NULL` column could be normalized to another table of deletions. Any null element could be an absent row in another table. But this is clearly only possible in theory
<FromGitter> <Blacksmoke16> true
<FromGitter> <nsuchy> okay so far so good
<FromGitter> <nsuchy> SQLite doesn't seem to be hit too hard performance wise
<FromGitter> <nsuchy> writing out those insert queries
<FromGitter> <tenebrousedge> how long does it take?
<FromGitter> <nsuchy> 500 keys took 3 seconds
<FromGitter> <nsuchy> there's a lot of tables though
<FromGitter> <nsuchy> I'm not using transactions yet either
<FromGitter> <nsuchy> just a bunch of single queries
<FromGitter> <Blacksmoke16> not bad
<FromGitter> <nsuchy> @tenebrousedge okay, looks like it might be time to reconsider transactions, been waiting like a few minutes on this block of code ⏎ ⏎ ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5cead7d283ae782aeed57f2b]
<FromGitter> <Blacksmoke16> gross
<FromGitter> <nsuchy> okay, 4 minutes and 15 seconds and they're inserted
<FromGitter> <nsuchy> so not instantly but eh, it's good enough I guess
<FromGitter> <nsuchy> and @Blacksmoke16 tell me there's a better way to write that code
<FromGitter> <Blacksmoke16> i wouldnt know without actually looking into it more, but was more so talking about all those trys
<FromGitter> <nsuchy> honestly
<FromGitter> <nsuchy> the trys are better than IF statement hell
<FromGitter> <tenebrousedge> I really strongly suggest adding `dig` to the class that your `item` object is using
<FromGitter> <tenebrousedge> `item.dig(:cve, :affects, :vendor, :vendor_data).map do |subitem|`
<FromGitter> <nsuchy> send me that code again for DIG
<FromGitter> <nsuchy> it's actually a struct
<FromGitter> <nsuchy> not a class
<FromGitter> <tenebrousedge> Structs can have methods defined, too
<FromGitter> <nsuchy> found it
<FromGitter> <nsuchy> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5cead98ad22ba766a203c8e2]
<FromGitter> <tenebrousedge> the code I was using was from here: https://github.com/crystal-lang/crystal/blob/master/src/json/any.cr#L134 ⏎ you would have to rewrite it slightly to traverse the objects you're working with
<FromGitter> <nsuchy> so just put that at the top of my struc?
<FromGitter> <tenebrousedge> actually, I think `Struct` has `[]`, so maybe not
<FromGitter> <tenebrousedge> you may be able to paste that in
<FromGitter> <tenebrousedge> you probably also need ⏎ ⏎ ``` def dig(key : String | Int) ⏎ self[key] ⏎ end``` [https://gitter.im/crystal-lang/crystal?at=5ceada310ac9852a954597bc]
<FromGitter> <nsuchy> What are some possible causes for the code taking 4 minutes on my macos machine, but much longer on a linux machine?
<FromGitter> <davidcolombogit> Hey Guys
<FromGitter> <davidcolombogit> What could cause Crystal not detecting the LLVM6 installation on my Ubuntu 18.04 Laptop?
<FromGitter> <tenebrousedge> probably something related to this https://github.com/crystal-lang/crystal/issues/5556
<FromGitter> <nsuchy> I'm using LLVM6 on my mac without an issue
<FromGitter> <nsuchy> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ceae527ecdf942b4c4dacec]
<FromGitter> <tenebrousedge> mmhmm
<FromGitter> <tenebrousedge> you can try using `LLVM_CONFIG=/usr/bin/llvm-config-6.0`
<FromGitter> <tenebrousedge> if it asplodes then don't do that
<FromGitter> <davidcolombogit> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ceae5827c363c75a749f5d1]
<jhass> the llvm version reported there is just what the package was compiled against, it includes LLVM statically
<jhass> which version you have installed alongside doesn't matter
<FromGitter> <tenebrousedge> 👀
<FromGitter> <davidcolombogit> Gotcha
* FromGitter * tenebrousedge has learned a thing
<FromGitter> <davidcolombogit> I install from source now anyways
<FromGitter> <nsuchy> jhass: It might be a good idea to include the actual version at runtime in --version
<FromGitter> <nsuchy> so people can see the difference
<jhass> there's no actual version
<FromGitter> <nsuchy> like the version of LLVM being used
<jhass> the one crystal is (statically) linked again is the one that gets run
<FromGitter> <nsuchy> vs the one its compiled with
<FromGitter> <nsuchy> can you change what's statically linked
<FromGitter> <nsuchy> or does it require a recompile
<jhass> it does
<jhass> that's the exact difference of static vs dynamic linking
<jhass> btw you cannot dynamically link LLVM
<FromGitter> <davidcolombogit> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ceae9029d64e537bc16afb5]
<FromGitter> <davidcolombogit> Hmm
<FromGitter> <davidcolombogit> Btw, are you aware of https://crystal-ann.herokuapp.com/ showing an error?
<FromGitter> <Blacksmoke16> i dont think thats for anything official
<FromGitter> <nsuchy> Any ideas on why my SQLite code takes 5 minutes on macOS but much longer on Linux
<FromGitter> <Blacksmoke16> are they separate computers?
<FromGitter> <nsuchy> yyes
<FromGitter> <nsuchy> a very high end linux box of @davidcolombogit vs my low end macbook pro
<FromGitter> <Blacksmoke16> does one have an SSD and the other a HDD?
<FromGitter> <nsuchy> both have SSDs
<FromGitter> <nsuchy> one is running Ubuntu 18.04 the other runs macos mojave
<FromGitter> <tenebrousedge> probably `fsync` related
<FromGitter> <Blacksmoke16> i could go with that
<FromGitter> <Blacksmoke16> we switched to https://github.com/bcpierce00/unison at work, quite noticeable improvement
<FromGitter> <Blacksmoke16> for syncing between mac and the vagrant
<FromGitter> <davidcolombogit> Well, if this is fsync related ⏎ I should switch to a Mac xD
<FromGitter> <nsuchy> its not fsync thogh, the sqlite db is local
<FromGitter> <nsuchy> there's no vms in use
<FromGitter> <Blacksmoke16> the db is still a file
<FromGitter> <nsuchy> what does fsync have to do with it
<FromGitter> <Blacksmoke16> dont know too much about it
<FromGitter> <nsuchy> @tenebrousedge have any ideas on a workaround
<FromGitter> <davidcolombogit> fsync: "synchronize a file's in-core state with storage device"
<FromGitter> <davidcolombogit> But if its really fsync I switch to a Mac ⏎ I can't believe that Ubuntu with fsync takes ages and MacOS needs 4 minutes
<FromGitter> <tenebrousedge> I mean, that's my best guess. The behavior does differ between platforms, and likely has an effect on writes
<FromGitter> <Blacksmoke16> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ceaf11b0ac9852a95464108]
<FromGitter> <Blacksmoke16> :thinking:
<FromGitter> <davidcolombogit> Btw, https://github.com/crystal-lang/crystal/issues/2789 this is still a thing
<FromGitter> <davidcolombogit> make spec causes an error for me
<FromGitter> <davidcolombogit> "make compiler_spec std_spec" works fine
<FromGitter> <nsuchy> @tenebrousedge Where does this factor in on servers?
<FromGitter> <nsuchy> Does it mean the parser is useless on Linux Servers and we will need Macs to build the database?
<FromGitter> <tenebrousedge> I don't know
<FromGitter> <nsuchy> Where could we learn more about the issue?
<FromGitter> <nsuchy> will the fsync issue be any different between SQLite and MySQL?
<FromGitter> <tenebrousedge> https://www.sqlite.org/faq.html#q19
<FromGitter> <davidcolombogit> I think so
<FromGitter> <nsuchy> @tenebrousedge So if I switch to a transaction the issue will go away?
<FromGitter> <davidcolombogit> No "Actually, SQLite will easily do 50,000 or more INSERT statements per second on an average desktop computer. But it will only do a few dozen transactions per second."
<FromGitter> <davidcolombogit> Transactions are the slow thing
<FromGitter> <nsuchy> so we need to group each insert statement into one big transaction?
<FromGitter> <tenebrousedge> one transaction would probably be faster
<FromGitter> <nsuchy> I have `DB.open "sqlite3://./src/example-json-files/dbname.sqlt" do |db| ... end`
<FromGitter> <nsuchy> what would I put inside to do a transaction with one query
<FromGitter> <nsuchy> (in production there would be several queries)
<FromGitter> <davidcolombogit> We would still need dozens of transactions to add more than a million rows xD
<FromGitter> <nsuchy> @davidcolombogit you're making the asumption a transaction can only have one query
<FromGitter> <nsuchy> in fact they can have several
<FromGitter> <davidcolombogit> Yes
<FromGitter> <davidcolombogit> But by default, each INSERT statement is its own transaction.
<FromGitter> <nsuchy> So we group them into one transaction
<FromGitter> <nsuchy> problem hopefully solved
<FromGitter> <davidcolombogit> What do you think about that
<FromGitter> <davidcolombogit> " ⏎ Another option is to run PRAGMA synchronous=OFF. This command will cause SQLite to not wait on data to reach the disk surface, which will make write operations appear to be much faster. But if you lose power in the middle of a transaction, your database file might go corrupt."
<FromGitter> <nsuchy> `tx.commit` is at the bottom
<FromGitter> <nsuchy> nothing gets written to the DB
<FromGitter> <tenebrousedge> so, one question is why you're not storing the raw json in SQLite https://www.sqlite.org/draft/json1.html and why SQLite is being used instead of Mongo or Postgres, which have even better JSON support
<FromGitter> <davidcolombogit> Well, MySQL should do the job also
<FromGitter> <nsuchy> any reason why transactions are doing nothing
<FromGitter> <Blacksmoke16> Did you commit the transaction
<FromGitter> <nsuchy> yes
<FromGitter> <nsuchy> tx.commit
<FromGitter> <nsuchy> Queries as `tx.connection.query("INSERT INTO IMPACT (ID, BASEMETRICV3, BASEMETRICV2) VALUES (?, ?, ?)", [cve_item_id, "", ""])`
<FromGitter> <nsuchy> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ceaf580ef853135c82a39f5]
<FromGitter> <nsuchy> sswitching from query to exec fixed
<FromGitter> <nsuchy> also
<FromGitter> <nsuchy> it takes mere seconds
<FromGitter> <nsuchy> not minutes
<FromGitter> <nsuchy> ```code paste, see link``` [https://gitter.im/crystal-lang/crystal?at=5ceaf6c575d9a575a64c5ed4]
<FromGitter> <davidcolombogit> push this to the repo!
<jhass> btw you an also insert multiple rows with one insert query: https://stackoverflow.com/a/5009740/2199687
<FromGitter> <nsuchy> already did @davidcolombogit
<FromGitter> <nsuchy> jhass: looking over that
<FromGitter> <nsuchy> SQLite transaction builder is so fast
<FromGitter> <tenebrousedge> so I take it the performance problems are considered fixed now?
<FromGitter> <tenebrousedge> let us know what the eventual speedup is vs nodejs
<FromGitter> <Blacksmoke16> and they're handled in the same way?
<FromGitter> <Blacksmoke16> because it would be easy to write some slow code, then refactor it in a better way to get a big improvement
<FromGitter> <Blacksmoke16> im just a bit skeptical that the lang change alone resulted in *that* big of an improvement
<FromGitter> <nsuchy> /shrug
<FromGitter> <nsuchy> A rewrite into Crystal forced us to use better practices
<FromGitter> <nsuchy> Crystal is at least partially responsible
<FromGitter> <tenebrousedge> 👍
<FromGitter> <jgaskins> That, I think, is one of the big wins with Crystal over other languages that goes unnoticed a lot.
<FromGitter> <davidcolombogit> Definitely
<FromGitter> <Blacksmoke16> i could go with that
<FromGitter> <jgaskins> You can gain a fair bit of performance by porting code directly and then tune it to use things like stack-based objects, replace allocations of large strings with direct IO, etc, and gain even more performance.
<FromGitter> <jgaskins> That last mile is unavailable in some languages.
<FromGitter> <nsuchy> Also SQLite bulk transactions are awesome
<FromGitter> <davidcolombogit> Signing off for today folks, have great night (or day depending on your country xD) ⏎ Thanks for the help so far!
<FromGitter> <Blacksmoke16> o/
<FromGitter> <jgaskins> 👋
<FromGitter> <nsuchy> 😄😄😄
ashirase has quit [Ping timeout: 246 seconds]
DTZUZU has quit [Ping timeout: 258 seconds]
ashirase has joined #crystal-lang
<FromGitter> <nsuchy> Crystal is amazing
<FromGitter> <nsuchy> Can not believe we got a 14 hour script to do the same job in just a second
<FromGitter> <Daniel-Worrall> Scripting is accessible but compiled is efficient
jokke2 is now known as jokke
jokke has quit [Quit: WeeChat 2.4]
jokke has joined #crystal-lang
<FromGitter> <Blacksmoke16> i noticed that yaml anchors are built before the key
<FromGitter> <Blacksmoke16> which kinda breaks my stuff :/
<FromGitter> <Blacksmoke16> https://play.crystal-lang.org/#/r/6zj8
<FromGitter> <Blacksmoke16> the 2nd value should be `Foo` since it should inherit from `development`, which works if the anchor is after the key
<FromGitter> <Blacksmoke16> hrm, well this is annoying
ashirase has quit [Ping timeout: 272 seconds]
ashirase has joined #crystal-lang
DTZUZU has joined #crystal-lang