Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic UDT implementation #406

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

ilanusse
Copy link
Collaborator

@ilanusse ilanusse commented Jan 12, 2019

Summary

I created a basic implementation for handling UDTs. It feels a bit off, so feel welcome to suggest changes that might be better. I wouldn't really say I understand Cequel's structure 100% since I haven't read through the entire codebase but I'm definitely ready to learn!

These changes work with Cassandra 3.6 upwards as seen in the Cassandra changelog.

I also bumped the cassandra-driver version but that commit can be removed.

On to the meat of this PR. Let's say we have this UDT:

CREATE TYPE cequel_test.person (name text, last_name text, age int);

You can create an object with a UDT column and set it with a hash, like so:

# Post.rb
class Post do
    include Cequel::Record
    key :permalink, :text
    column :title, :text
    udt :author, :person
end

# somewhere in your code
Post.create(permalink: 'cequel', author: { name: 'Inaki', last_name: 'Lanusse', age: 24 })

To update it, we have to overwrite the entire hash, as I couldn't get atomic modification working yet.

# somewhere else in your code
post.author = { name: 'Iñaki', last_name: 'Lanusse', age: 25 }
post.save!
post.author #  { name: 'Iñaki', last_name: 'Lanusse', age: 25 }

Design Choices

I decided to go for the syntax udt :name, :type rather than something like column :name, :udt, type: :type to stay true to the way collection columns are defined, and to dissuade users from wanting to use UDTs as key columns, which I don't really think is a good idea. I'm aware UDTs are not collection columns but you get the idea. It's not a scalar column.

Issues

#263

Pending for other PRs

  • A Rake task that allows you to generate UDTs similar to how rake cequel:migrate works
  • UDT atomic modification
  • Implement frozen types so we can have UDTs for earlier versions

@pezra
Copy link
Contributor

pezra commented Jan 14, 2019

This is awesome. I haven't had a chance to look at the code yet but I'm stoked to have this functionality.

@pezra
Copy link
Contributor

pezra commented Jan 14, 2019

I should be able to review this week.

# -*- encoding : utf-8 -*-
require File.expand_path('../spec_helper', __FILE__)

describe Cequel::Record do
Copy link
Collaborator Author

@ilanusse ilanusse Jan 14, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't too sure what to put here since I didn't really define a class to represent a UDT since Cassandra::UDT handles it pretty well

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is basically fine, but can you add a description suffix like describe Cequel::Record, "UDT support" do

Copy link
Contributor

@pezra pezra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is looking good. i do have some minor concerns. my biggest is that i think we need a better way to define types. my second concern is that is don't love using Hash as the class for all UDTs.

regarding defining types, what if we added them to keyspace schema? that would allow the schema sync to create them. this might allow us to address my second concern too. consider an approach like

class Person do
  include Cequel::UDT

  field :name, :text
  field :age, :int
end

this could then be wired into the existing type casting system, https://github.com/cequel/cequel/blob/master/lib/cequel/type.rb, so that we use the same code for UDTs as other types.

module_eval <<-RUBY, __FILE__, __LINE__+1
def #{name}
value = read_attribute(#{name.inspect})
(value.is_a? Cassandra::UDT) ? value.to_h.symbolize_keys : value
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe value.to_h.symbolize_keys! to reduce the GC load?

# @api private
#
def cast(value)
Cassandra::UDT.new(value.to_h)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we really need to convert it to a hash? what if we just passed value to #new?

class UdtColumn < DataColumn
#
# @param value the value to cast
# @return the value cast as a hash
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems this code returns a Cassandra::UDT not a hash.

# -*- encoding : utf-8 -*-
require File.expand_path('../spec_helper', __FILE__)

describe Cequel::Record do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is basically fine, but can you add a description suffix like describe Cequel::Record, "UDT support" do


describe Cequel::Record do
model :Post do
connection.execute("CREATE TYPE cequel_test.person (name text, last_name text, age int)")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we have better syntax for type creation?

@ilanusse ilanusse self-assigned this Oct 31, 2019
@ilanusse
Copy link
Collaborator Author

Alright, I'm going to try and get this done during the first two weeks of November

@devnut
Copy link

devnut commented Jun 17, 2020

Can this feature please get implemented? Its a really important feature of Cassandra thats unavailable in Cequel.

  • Greg

@pezra
Copy link
Contributor

pezra commented Jul 21, 2020

@devnut, you are welcome to take this PR over and complete it if you'd like

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants