[jira] [Comment Edited] (ACCUMULO-4746) Create Builder for Mutation

2017-12-07 Thread Benjamin F (JIRA)

[ 
https://issues.apache.org/jira/browse/ACCUMULO-4746?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16274743#comment-16274743
 ] 

Benjamin F edited comment on ACCUMULO-4746 at 12/7/17 1:27 PM:
---

I like the idea of a Fluent interface in this context. It works well since we 
certainly can't set everything in the constructor and lends well to creating 
mutations; fluency comes from making a new value from an old one which we 
always do with mutations. Plus this covers your use case of the caller just 
being able to chain overloaded methods such as 
{{someMutation.mutate().family(foo)}} without having too much concern if foo is 
a String or byte[]. 

My only (very small) concern is how well it will be able to flow semantically. 
I think changing the name of the {{mutate()}} method as you mentioned in the 
code comment could solve this, having the action word mutate near the front of 
the chain seems like an action is being taken before I as the caller have set 
the values. This is the only potential change I could think of but I think the 
'new' term in my function name could be misleading and doesn't necessarily 
match up with what's in the {{Mutation}} class:

{code:java}
m1.newRowChange()
.family(fam)
.qualifier("q1")
.set("v1")
{code}

Using {{newRowChange}} matches up with the verbiage in the Accumulo book 
(pg.29, Introduction to the Client API) where the {{Mutation}} object is 
described as a set of changes applied to a single row. Having {{set()}} be the 
only action word in the chain makes it more apparent as an end to the chain. 
Overall I think this is a great direction to go.


was (Author: bmfach):
I like the idea of a Fluent interface in this context. It works well since we 
certainly can't set everything in the constructor and lends well to creating 
mutations; fluency comes from making a new value from an old one which we 
always do with mutations. Plus this covers your use case of the caller just 
being able to chain overloaded methods such as 
`someMutation.mutate().family(foo)` without having too much concern if `foo` is 
a String or byte[]. 

My only (very small) concern is how well it will be able to flow semantically. 
I think changing the name of the `mutate` method as you mentioned in the code 
comment could solve this, having the action word mutate near the front of the 
chain seems like an action is being taken before I as the caller have set the 
values. This is the only potential change I could think of but I think the 
'new' term in my function name could be misleading and doesn't necessarily 
match up with what's in the `Mutation` class:

`m1.newRowChange()
.family(fam)
.qualifier("q1")
.set("v1")`

Using `newRowChange` matches up with the verbiage in the Accumulo book (pg.29, 
Introduction to the Client API) where the `Mutation` object is described as a 
set of changes applied to a single row. Having `set()` be the only action word 
in the chain makes it more apparent as an end to the chain. Overall I think 
this is a great direction to go.

> Create Builder for Mutation
> ---
>
> Key: ACCUMULO-4746
> URL: https://issues.apache.org/jira/browse/ACCUMULO-4746
> Project: Accumulo
>  Issue Type: Sub-task
>  Components: client
>Reporter: Keith Turner
>Assignee: Benjamin F
> Fix For: 2.0.0
>
>
> Accumulo needs a builder for mutation similar to the one that was added for 
> Key.



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)


[jira] [Comment Edited] (ACCUMULO-4746) Create Builder for Mutation

2017-12-06 Thread Keith Turner (JIRA)

[ 
https://issues.apache.org/jira/browse/ACCUMULO-4746?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16280640#comment-16280640
 ] 

Keith Turner edited comment on ACCUMULO-4746 at 12/6/17 6:38 PM:
-

Another entry point function to consider is {{for()}}.  What I like about 
{{for()}} is that it reads a bit like a sentence (e.g. For the family X and 
qualifier Y set the value to Z.)

{code:java}
 m1.for().family(fam).qualifier("q1").set("v1");
 m1.for().family(fam).qualifier("q2").set(bb);
 m1.for().family(fam).qualifier("q3").delete();
{code}

I think I like {{at()}} more than {{for()}}. 


was (Author: kturner):
Another entry point function to consider is `for()`.  What I like about `for()` 
is that it reads a bit like a sentence (e.g. For the family X and qualifier Y 
set the value to Z.)

{code:java}
 m1.for().family(fam).qualifier("q1").set("v1");
 m1.for().family(fam).qualifier("q2").set(bb);
 m1.for().family(fam).qualifier("q3").delete();
{code}

I think I like `at()` more than `for()`. 

> Create Builder for Mutation
> ---
>
> Key: ACCUMULO-4746
> URL: https://issues.apache.org/jira/browse/ACCUMULO-4746
> Project: Accumulo
>  Issue Type: Sub-task
>  Components: client
>Reporter: Keith Turner
>Assignee: Benjamin F
> Fix For: 2.0.0
>
>
> Accumulo needs a builder for mutation similar to the one that was added for 
> Key.



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)


[jira] [Comment Edited] (ACCUMULO-4746) Create Builder for Mutation

2017-11-28 Thread Keith Turner (JIRA)

[ 
https://issues.apache.org/jira/browse/ACCUMULO-4746?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16269423#comment-16269423
 ] 

Keith Turner edited comment on ACCUMULO-4746 at 11/28/17 8:43 PM:
--

While trying to puzzle through the issues I was running into with 
ConditionalMutation I thought about this issue more deeply. I came to the 
conclusion that a builder is not the right path for Mutation.  For Key it made 
more sense because Key had a lot of constructors and no setters.  However for 
mutation, it has all of these put methods.  So after creating a mutation with a 
builder, its possible to call put methods to further change it. This seems 
silly to me.

What is nice about the key builder is that it allows easy mixing of different 
types.  For example its easy to have a byte array for the row, String for the 
family, and byte array for the qualifier.  Currently this is not possible with 
the mutation put methods.  There are put methods for all byte arrays or all 
strings, but not combinations.  

Based on the reasons above, I think having a fluent way to mix types for an 
existing mutation instead of a builder is a better path.  If we were designing 
the API from scratch I think a builder that creates immutable mutations would 
be the way to go.  However that is not an option for the current API.  Below is 
a proposed Fluent API for mutating that easily supports mixing types.

{code:java}
class Mutation {
  public interface FamilyStep extends QualifierStep {
// TODO other types?
QualifierStep family(CharSequence f);

QualifierStep family(byte[] f);

QualifierStep family(ByteBuffer f);
  }

  public interface QualifierStep extends VisibilityStep {
// TODO other types?
VisibilityStep qualifier(CharSequence q);

VisibilityStep qualifier(byte[] q);

VisibilityStep qualifier(ByteBuffer q);
  }

  public interface VisibilityStep extends TimestampStep {
// TODO other types?
TimestampStep visibility(CharSequence cv);

TimestampStep visibility(byte[] cv);

TimestampStep visibility(ByteBuffer cv);

TimestampStep visibility(ColumnVisibility cv);
  }

  public interface TimestampStep extends MutateStep {
MutateStep timestamp(long t);
  }

  public interface MutateStep {
// TODO other types?
void set(byte[] v);

void set(ByteBuffer v);

void set(CharSequence v);

void delete();
  }

  // this could be called put... 
  public FamilyStep mutate() {
//TODO implement.. could return a private inner class that implements all 
interfaces...
return null;
  }
}
{code}

Below is an example of using the new API that shows easily mixing different 
types

{code:java}
Mutation m1 = new Mutation("row1");

byte[] fam = new byte[] {42, 21, 7, 9, 3, 34};
ByteBuffer bb = ...;

m1.mutate().family(fam).qualifier("q1").set("v1");
m1.mutate().family(fam).qualifier("q2").set(bb);
m1.mutate().family(fam).qualifier("q3").delete();

ByteBuffer bb2 = ...;

//below is an example of using the existing put method with different types
byte[] tmp = new byte[bb2.remaining()];
bb2.put(tmp);
// must make all types same, so made all into byte arrays
m1.put(fam, "q4".getBytes(StandardCharsets.UTF_8), tmp);
{code}


was (Author: kturner):
While trying to puzzle through the issues I was running into with 
ConditionalMutation I thought about this issue more deeply. I came to the 
conclusion that a builder is not the right path for Mutation.  For Key it made 
more sense because Key had a lot of constructors and no setters.  However for 
mutation, it has all of these put methods.  So after creating a mutation with a 
builder, its possible to call put methods to further change it. This seems 
silly to me.

What is nice about the key builder is that it allows easy mixing of different 
types.  For example its easy to have a byte array for the row, String for the 
family, and byte array for the qualifier.  Currently this is not possible with 
the mutation put methods.  There are put methods for all byte arrays or all 
strings, but not combinations.  

Based on the reasons above, I think having a fluent way to mix types for an 
existing mutation instead of a builder is a better path.  If we were designing 
the API from scratch I think a builder that creates immutable mutations would 
be the way to go.  However that is not an option for the current API.  Below is 
a proposed Fluent API for mutating that easily supports mixing types.

{code:java}
class Mutation {
  public interface FamilyStep extends QualifierStep {
// TODO other types?
QualifierStep family(CharSequence f);

QualifierStep family(byte[] f);

QualifierStep family(ByteBuffer f);
  }

  public interface QualifierStep extends VisibilityStep {
// TODO other types?
VisibilityStep qualifier(CharSequence q);

VisibilityStep qualifier(byte[] 

[jira] [Comment Edited] (ACCUMULO-4746) Create Builder for Mutation

2017-11-28 Thread Keith Turner (JIRA)

[ 
https://issues.apache.org/jira/browse/ACCUMULO-4746?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16269132#comment-16269132
 ] 

Keith Turner edited comment on ACCUMULO-4746 at 11/28/17 5:47 PM:
--

I was experimenting with an API for this builder and came up with the following.

{code:java}
class Mutation {
  public interface Builder extends QualifierStep {

// TODO other types
QualifierStep family(CharSequence f);

public Mutation build();
  }

  public interface QualifierStep extends VisibilityStep {
// TODO other types
VisibilityStep qualifier(CharSequence q);
  }

  public interface VisibilityStep extends TimestampStep {
// TODO other types
TimestampStep visibility(CharSequence v);
  }

  public interface TimestampStep extends MutateStep {
// TODO other types
MutateStep timestamp(long t);
  }

  public interface MutateStep {
Builder set(CharSequence v);

Builder delete();
  }

  //TODO support other types for row
  public static Builder builder(CharSequence row) {
return null; // TODO
  }
}
{code}

Using the API above, can write code like the following to create mutations.

{code:java}
Builder builder = Mutation.builder("row1");

builder.family("f1").qualifier("q1").set("v1");
builder.family("f1").qualifier("q2").delete();
builder.qualifier("q1").set("v2"); // empty family

Mutation m = builder.build();

Mutation m2 = Mutation.builder("row1")
.family("f1").qualifier("q1").set("v1")
.family("f1").qualifier("q2").set("v2")
.family("f1").qualifier("q3").delete()
.family("f2").visibility("A").set("v3") // empty qualifier

.family("f3").qualifier("q1").visibility("A|B").timestamp(56).set("v4").build();
  }
{code}


was (Author: kturner):
I was experimenting with an API for this builder and came up with the following.

{code:java}
class Mutation {
  public interface Builder extends QualifierStep {

// TODO other types
QualifierStep family(CharSequence f);

public Mutation build();
  }

  public interface QualifierStep extends VisibilityStep {
// TODO other types
VisibilityStep qualifier(CharSequence q);
  }

  public interface VisibilityStep extends TimestampStep {
// TODO other types
TimestampStep visibility(CharSequence v);
  }

  public interface TimestampStep extends MutateStep {
// TODO other types
MutateStep timestamp(long t);
  }

  public interface MutateStep {
Builder set(CharSequence v);

Builder delete();
  }

  //TODO support other types for row
  public static Builder builder(CharSequence row) {
return null; // TODO
  }
}
{code}

Using the API above, can write code like the following to create mutations.

{code:java}
Builder builder = Mutation.builder("row1");

builder.family("f1").qualifier("q1").set("v1");
builder.family("f1").qualifier("q2").delete();
builder.qualifier("q1").set("v2"); // empty qualifier

Mutation m = builder.build();

Mutation m2 = Mutation.builder("row1")
.family("f1").qualifier("q1").set("v1")
.family("f1").qualifier("q2").set("v2")
.family("f1").qualifier("q3").delete()
.family("f2").visibility("A").set("v3") // empty qualifier

.family("f3").qualifier("q1").visibility("A|B").timestamp(56).set("v4").build();
  }
{code}

> Create Builder for Mutation
> ---
>
> Key: ACCUMULO-4746
> URL: https://issues.apache.org/jira/browse/ACCUMULO-4746
> Project: Accumulo
>  Issue Type: Sub-task
>  Components: client
>Reporter: Keith Turner
> Fix For: 2.0.0
>
>
> Accumulo needs a builder for mutation similar to the one that was added for 
> Key.



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)