2nd alpha release of "Create a cryptocurrency trading bot in Elixir" is out
2nd alpha release of my book is out! 3 new chapters. @ 50% finished, it’s about 145 pages long and has 12 chapters. Early bird access, pay what you want (although some $$$ would be totally cool with me :D)
https://leanpub.com/create-a-cryptocurrency-trading-bot-in-elixir
Feel free to reach out if you found any issue / drop a comment / say hi :)
Have a wonderful Sunday,
Kamil
Phoenix UI testing with Cypress, Part 1
Adding Cypress UI testing/end-to-end testing to a Phoenix project. In Part 1, it’s all about setup and getting a first test to run. Find the article at https://sgoettschkes.me/p/phoenix-testing-with-cypress.html
Elixir Wizards S5E10 Alexandra Chakeres on Moving Towards an Inclusive Elixir Community
Latest episode of Elixir Wizards is out today! Check it out here: https://smartlogic.io/podcast/elixir-wizards/s5e10-chakeres/
TimescaleDB support in Elixir using Ecto
Most of the projects collect a lot of data. It usually means a heavy loads on the database. What can we do to provide better request handling and lower access times? See how to integrate Elixir and Ecto with one, very popular extension for PostgreSQL database which is TimescaleDB.
https://bartoszgorka.com/timescaledb-support-in-elixir-using-ecto
Fat Fingered Input
I made a simple LIveview form to reduce data input errors https://andrewbarr.io/posts/fat-finger-input
How to use String UUID in Hibernate with MySQL
Article originally posted on my personal website at How to use String UUID in Hibernate with MySQL - Petre Popescu
When creating the database structure it is important to make sure that each row in a table has a unique ID so that it can be easily indexed, retrieved, and manipulated when needed. The most common methods are to use an auto-incremented column or a generated UUID.
I won’t be covering the auto-incremented method since it poses no real problems and can be mapped to an Integer in the Java domain class. When using an UUID, this can pose some tricks, depending on the configuration and MySQL version. The good news is that there is an easy way of mapping the Java UUID column to MySQL using Hibernate and no additional libraries are needed.
First, let’s look at the a sample table. I will be using a simplified version of a USERS table that stores login information for each registered user to a site. We will need the following information:
- ID
- Name
- Password Hash*
*This is a simplified structure and only has a minimum number of columns. Storing an unsalted password hash is not recommended. Look up best practices of storing passwords in the database when creating the final structure. We want the ID to be unique so we will be using the Java UUID in our domain object. Because we want all the information to be human readable as well, the ID should be stored as a String. Since we know the format of the UUID when represented as a String, we know that it has a length of 36 characters, so we can define the column as VARCHAR(36). The rest of the table structure can be similar to the image.
Now, we create our domain class using Hibernate annotations to map it to our existing MySQL table.
@Entity
@Table(name = "users")
public class UserDO {
@Id
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Column(name = "id", updatable = false, nullable = false, columnDefinition = "VARCHAR(36)")
private UUID id;
@Column
private String username;
@Column
private String email;
@Column(name = "password_hash")
private String passwordHash;
}
We expect that everything works as intended and that Hibernate knows how to map the UUID to the VARCHAR(36) column, but this is only partially true. When executing the code and trying to do an insert, an java.sql.SQLException will be thrown:
java.sql.SQLException: Incorrect string value: '\xE3\xAF\xF7d\x0CG…' for column 'id' at row 1
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:129)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1092)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1040)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1347)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1025)
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)
This is because Hibernate tries to insert it as Binary data instead of String. There are two options at the moment. First, we can change the column of the ID in the database to be of type BINARY. This will solve the problem and inserting a new user will be successful. However, in doing so, the ID is no longer human-readable and it can be difficult in the future to debug, analyze logs, or manually manipulate the entries.
What we want is to have a String UUID column using Hibernate without the need to do any further manipulation in the code. This is where a new annotation comes into play: @Type
@Entity
@Table(name = "users")
public class UserDO {
@Id
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Column(name = "id", updatable = false, nullable = false, columnDefinition = "VARCHAR(36)")
@Type(type = "uuid-char")
private UUID id;
@Column
private String username;
@Column
private String email;
@Column(name = "password_hash")
private String passwordHash;
}
This annotation defines the Hibernate type mapping. Using “uuid-char” instructs Hibernate to store the UUID as a String, instead of the binary value. This way, it can be written to and read from a VARCHAR(36) column without the need for any pre-processing on our side.
ThinkingElixir 033: Postgres PubSub and Elixir with Allen Wyma
In episode 33 of Thinking Elixir, we talk with Allen Wyma about a Postgres PubSub feature and how it plays nice with Elixir. We dispel the idea that you should always use Phoenix PubSub just because it’s there and we cover the value of learning what’s built-in to tools like the postgrex library. Allen shares how Postgres PubSub elegantly solved a problem for him and he gives tips for using it. We also talk about teaching Elixir through Allen’s YouTube videos and teaching in person with his Teach Me Code efforts.
UUID Primary Key in Elixir Phoenix with PostgreSQL and Ecto
https://pawelurbanek.com/elixir-phoenix-uuid
UUID also known as GUID is an alternative primary key type for SQL databases. It offers some non-obvious advantages compared to standard integer-based keys. Phoenix provides reliable support for working with UUID using its Ecto PostgreSQL adapter. In this tutorial, we will dive deep into UUIDs with all their cons and pros.
Top 3 Tough Elixir Fights |Debugging in Production | 2020
The top 3 challenges faced in production runtime & debugging them.
https://medium.com/blackode/top-3-tough-elixir-fights-debugging-in-production-2020-6ab712a2c8f4
This article isn’t about how to code. It talks about some experiences with Elixir
TQ Happy Coding :)
Connecting to a FTP server with Elixir
I recently had to connect to FTP servers with Elixir, here are my findings: https://thibautbarrere.com/2020/12/13/connecting-to-ftp-with-elixir
Using LiveView and GenServers to track BTC price
Short tutorial on how to use Elixir to track BTC prices: https://cmdarek.com/pages/using-liveview-and-genservers-to-track-btc-price.html
12th episode - Autostarting trading strategy ROUND 2 - crypto trading in Elixir
12th video in the series about building cryptocurrency trading bot in Elixir - this time we will focus on leveraging the Task abstraction to simplify the autostarting and supervision tree of the Naive application. We will look into how we could stop tracking the trading symbols and drop the Naive.Server altogether.
Link: https://www.youtube.com/watch?v=2_HIohZPT_Q&list=PLxsE19GnjC5Nv1CbeKOiS5YqGqw35aZFJ&index=12
Frontend setup with Vite.js for Phoenix + Liveview
In this post: https://mindreframer.com/posts/js-bundling-with-instant-live-reload-for-phoenix-and-liveview/ I outline required steps to make Vite.js work properly with Phoenix. This helps greatly during local development, because it applies changes directly in the browser, without going through the JS re-bundling step.
The resulting code is here: https://github.com/mindreframer/phx-vite-demo. I am mostly interested in feedback and ideas how to make it more approachable and convenient.
Hope you enjoy it!
Backend Engineer (Elixir) at Fresha
Come and work as an Elixir Back-End Engineer in the Engineering team at Fresha! We’re a fast-growing global platform that is revolutionizing the beauty and wellness industry. Fresha has quickly become a game-changing industry leader which is transforming how beauty and wellness owners run their businesses and how consumers find and consume their products and services.
All over the world, our customers book over 10 million appointments every month, with thousands of partner businesses worldwide (currently 45,000 and growing every day). We recently passed a significant business milestone of having processed $10B of bookings with our platform.
Given our scale, and our continued growth, we are looking to find the best engineers to come and join us on our mission.
Phoenix scaffolding generator which uses Tailwind CSS
I published a Phoenix scaffold generator which doesn’t use the default Milligram CSS but Tailwind CSS. https://github.com/wintermeyer/phx_tailwind_generators
Should be very interesting for everybody who is boarding the PETAL train.
Elixir Wizards S5E9 Brian Cardarella on Adopting Elixir
Latest episode of Elixir Wizards is out today! Check it out here: https://smartlogic.io/podcast/elixir-wizards/s5e9-cardarella/
Senior Backend (Elixir) position at Remote
Hey there! Remote is THE global platform that enables companies to employ people anywhere in the world, taking away all legal and compliance complexities. We do this using our own SaaS platform created on Elixir and Phoenix. We’re fully remote, we work asynchronously and use a simple approach to productivity and task management. We live our values and you can see exactly how we are in our public handbook. We’re growing and we need to expand our engineering team. If you have 2+ years of working experience with Elixir, why not consider joining us? Thank you!
ThinkingElixir 032: Circuit Breaker and Elixir Patterns with Allan MacGregor
In episode 32 of Thinking Elixir, we talk with Allan MacGregor about implementing the Circuit Breaker pattern in Elixir and compare that to just using a job library. We get into a fun discussion about design patterns in Elixir and designing for failure. Allan is creating a project called Site Guardian using the PETAL stack and shares his experiences with it and much more!
ex_check v0.14: new automations & curated tools to supercharge your Elixir workflow
Just released v0.14 of ex_check - a single task that runs all analysis & testing tools in Elixir projects. It comes with a load of new features that build upon ex_check’s “drop in solution” design to bring in even more time-saving automation so you can spend more time coding & less time waiting for CI to spit out issues.
-
Fix mode resolves issues automatically for tools that provide the fix command - useful on local machines for checking & fixing in one-shot and on CI for committing automatic fixes
-
Automatic toggling of retry mode when previous run resulted in failures allows to simply call task again after failures to do a faster check focused only on tools with issues
-
Capability to run only failed tests for tools themselves complements the retry mode and further optimizes the issue fixing workflow by re-checking only what has failed
-
Doctor tool ensures that the project documentation is healthy by validating the presence of module docs, functions docs, typespecs and struct typespecs
…and a few smaller improvements. Enjoy!
IntelliJ Elixir v11.9.2
Changelog
Bug Fixes
-
Protect from nested heredocs in documentation from stopping documentation’s heredoc as happens in
ModuleandEcto.Query.-
Use
~Sfor@moduledoctoo, in addition to@doc. -
Check if the documentation contains
“””or‘’’and use the opposite one as the promoter/terminator.-
If neither is used, use
“””. -
If both are used, use
“””, but then escape“””as\”\”\”.
-
If neither is used, use
- Trim trailing whitespace from documentation lines to match formatter output.
-
Use
-
Set
runIdemaxHeapSizeto7g- Set to the same I run my own IDE at, so the debugged instance isn’t any slower than the normal IDE when I need to do extended all day testing to trigger bugs.
-
Test that all
FormattingTestfiles can be parsed. -
YYINITIALis special - wrappers of the lexer assume that if inYYINITIAL, it is safe to shift the lexer over when there is an error, having{OPENING_CURLY}pushAndBegin(YYINITIAL)when it was either inYYINITIALorINTERPOLATIONmeans that the lexer looked like it was restartable when it really wasn’t. This code has been in the lexer for 6 years.-
When in
YYINITIAL,{no longer recurses intoYYINITIALas}does not need to be counted to determine if it is closing an interpolation. -
When in
INTERPOLATION,{entersINTERPOLATION_CURLYto allow counting and matching of}until it can exit and go back toINTERPOLATION, where}will exit the interpolation. -
When in
INTERPOLATION_CURLY,{enters another level ofINTERPOLATION_CURLYto allow counting and matching of}until it can exit and go up a level.
-
When in
-
The
}inYYINITIALdidyybegin(ADDITION_OR_SUBTRACTION_MAYBE), but it should have beenpushAndBegin(ADDITION_OR_SUBTRACTION)asADDITION_OR_SUBTRACTION_MAYBEor its following states all exit withhandleInLastState()orpopAndBegin(). This was not caught in #1859 because the extraYYINITIALfrompushAndBegin(YYINTIAL)hid the bug. -
Prevent nested
YYINITIALbugs in the future by erroring-
If trying to
pushAndBegin(YYINITIAL). -
If trying to
push(YYINITIAL)and the state stack is not empty
-
If trying to
-
Clear the state Stack when
ElixirFlexLexer#resetis called, as at the level of typing and pasting, theElixirFlexLexeris wrapped in many layers of lexers includingLexerEditorHighlighterwhere theElixirFlexLexeris no longer re-instantiated when there is no text, but instead,ElixirFlexLexer#resetis only called. This has always been an invariant violation since the stack state was added 7 years ago. It likely only became more apparent with the changes to +/- parsing in #1859 that made return-to-YYINITIALless likely.-
Since this
stack.clear()has to be manually added toElixirFlexLexer.java, which is generated fromElixir.flex,ResetTestis added to check that the code is still there.
-
Since this
-
For a reason I haven’t been able to explain, the
LexerEditorHighlighterstops working after:is typed at the start of an atom in certain situations, such as before)inside a function call, like when adding an argument. In this case, the old version of the lexer would mark)as aBAD_CHARACTERand continue to do so until an expected atom start of [a-zA-Z_],‘,“, or an operator occurred. Now, if an invalid atom start is matched, theATOM_STARTstate ends and the previous state handles the text, which in the function case mean)is parsed asCLOSING_PARENTHESIS. This change allows the highlighting to continue. I do not know if returningBAD_CHARACTERwill always break theLexerEditorHighlighter, but I don’t think, so since theGroovyLexerinintellij-communityreturns it, but it may be the case that it isn’t actually returned ever when users are typing and only handled by the lexer for completeness. Installation Instructions
