← Home About Archive Photos Projects Uses Also on Micro.blog
  • Today I Learned ~D[2025-06-02]

    File this under “things I knew but have to look up everytime”…

    If you want to spin up a Docker container without a service like postgres , for example if you had a fully seeded DB on your machine and didn’t want to go through the hassle of copying/re-seeding in Docker, you can do so with host.docker.internal. In docker-compose.yml you can write:

    environment:
          - DB_HOST=host.docker.internal
          - DB_PORT=5432
          - DB_USERNAME=your_pg_user
          - DB_PASSWORD=your_password
          - DB_NAME=your_db
    

    Because I switch projects a lot (agency life) there are occasions where a legacy codebase just stops working (system updates, depercations, etc.) at times like these I like falling back to the Docker container (upgrading the project is not always an option) but I may not want to loose/copy all my data from when I worked on the project before. Yes, I know dev data should be ephemeral and easy to reseed but in the real world this is not always how things work!

    → 8:00 PM, Jun 1
  • Today I Learned ~D[2025-05-22]

    There is only one false in Ruby… Or more broadly speaking since everything is an object, for the sake of efficency in memory management any object that can be referenced will be. Immutable primitives (such as true, false, 1, 2, etc.) will only ever reference themselves. For example:

    false.object_id
    => 0
    false.dup.object_id 
    => 0
    val = false 
    val.object_id 
    => 0
    

    Duplicating false only creates a reference to false. As opposed to a mutable primitive like a string:

    train = "choo choo"
    train.object_id 
    => 784160
    train.dup.object_id
    => 784180
    

    Of course this intuitively makes sense but I had never run up against it until I had a spec fail:

    expect(response[:enabled]).to be true
    expect(response[:value]).to be "location"
    
    => expected #<String:140300> => "location"
      got #<String:140320> => "location"
    

    I did a double take before I realized that the object_ids were different. The first spec passes because true is in immutable object. The second one fails because location is not! Fix that with: expect(response[:value]).to eq "location"

    → 8:00 PM, May 21
  • Today I Learned ~D[2025-01-10]

    Today’s TIL has a twist ending… so stick around.

    Elixir has a shortcut for creating anonymous functions. I’ve always written:

    greet = fn name -> "Hello, #{name}!" end 
    # which can be invoked
    greet.("Travis")
    # returns
    "Hello, Travis!"
    

    However; I came across some tricky code with a case statement:

    docs = case type do 
    	:billing -> &[billing_act: &1]
        :shipping -> &[shipping_act: &1]
    end 
    
    # invocation
    type = :billing
    docs.("some customer")
    # returns 
    [billing_act: "some customer"]
    

    This was very confusing to me, the fact that the anonymous function was a case form only further obfuscated what was happening. I thought it might be some case magic.

    No. Apparently you can short cut the aforementioned anonymous function declaration:

    greet = & "Hello, #{&1}!"
    

    You treat this as any other anonymous function. You can even have multi-arity functions:

    greet = & "Hello, #{&1} #{&2}!"
    # invocation 
    greet.("Travis", "Fantina")
    # returns 
    "Hello, Travis Fantina!"
    

    In my case the case statement could have also been written:

    docs = fn customer -> 
    	case type do
    		:billing -> [billing_act: customer]
        	:shipping -> [shipping_act: customer]
    	end
    end
    

    Plot twist: This is not a TIL, apparently I learned this at least four years ago. That initial case function… the author was me four years ago!

    → 8:00 PM, Jan 9
  • TIL Struct matching in Guards

    Not so much a TIL but I always get confused with the proper syntax. You can pattern match on a struct and use it in a guard to only let through the structs you want:

    @spec address_formater(BillAddress.t() | ShipAddress.t()) :: String.t()
    def address_formatter(%struct{} = address) when struct in [BillAddress, ShipAddress] do
     ...
    end 
    
    def address_formatter(_), do: raise "AddressError :: Not my address!"
    

    As with a lot of my examples it may be a little contrived but it is based on a real world but I fixed today where address_formatter/2 was getting an %Ecto.Association.NotLoaded{} and trying to format it.

    → 8:00 PM, Oct 9
  • TIL UUIDv4 vs UUIDv7

    I’ve always run with UUID v4 because it’s the default for the Ecto.UUID library in Elixir. However a coworker recommended UUID v7. Having never really looked into UUID other than to implement as a primary key the distinction was news to me.

    Effectively;

    • UUID v4 is a totally random hash that is generated and extremely unlikely to ever conflict with any other generated UUID.
    • UUID v7 also contains a random hash but is also based on a timestamp, this means you can sort them and index them.

    For further reference, yes there are UUIDs v1-v8 as of this writing. If you want a good description of each you can check out this helpful link .

    → 8:00 PM, Sep 24
  • TIL INSERT INTO with SELECT constraints

    In the past month I’ve had to write a lot of SQL to migrate a system and split existing “locations” into tenants ie. migrating data from a public schema to a tenant’s schema is gets messy due to foreign key constraints. Order of operations is important but sometimes you still find yourself in a corner.

    In instances where I already have data in the tenant schema, for example customers and I need to load a subset of data from another table, eg. customer_addreses it’s possible to run the query with tenant.customers as a constraint for what your inserting:

    INSERT INTO tenant.customer_addresses SELECT * FROM public.customer_addresses AS pc WHERE EXISTS (SELECT 1 FROM tenant.customers AS tc WHERE tc.id == pc.customer_id)
    

    This will insert public.customer_addresses into tenant.customer_addresses for every teant.customer that already exists. I’ve gotten around a lot of tricky constraint issues with missing/incomplete data this way.

    → 8:00 PM, Sep 17
  • RSS
  • JSON Feed
  • Micro.blog