Can I replace values in a table with SpecFlow.Assist? - cucumber

I currently have a step to verify a payment
Then I have these payments:
| Payment Type | Amount |
| Cash | 1.20 |
I would like to replace the 'Amount' with a variable, such as bill total which would be in the TestContext.
Then I have these payments:
| Payment Type | Amount |
| Cash | <billTotal> |
I've attempted to pre-process the table before creating my set, but I cannot assign to the TableRow value. Is there a standard way to achieve this? Is there a different approach I should be taking?

I ended up using something like this before creating my set:
public void AdjustTable(Table table)
{
foreach (var row in table.Rows)
{
foreach (var key in row.Keys)
{
if (row[key] == "<userFirstName>")
{
row[key] = this.testContext.CustomerProfile.Customer.Name.First;
}
else if (row[key] == "<userLastName>")
{
row[key] = this.testContext.CustomerProfile.Customer.Name.Last;
}
}
}
}
Still open to suggestions!!

Related

Retrieving Parents and Children - Self Referencing Entity gorm

I have a table that have a hierarchy structure with a parent having many children and a children having many parents.
As an example the following struct:
type User struct {
gorm.Model
Name string
SubUsers []*User `gorm:"many2many:user_sub_users;constraint:OnDelete:CASCADE"`
SuperUsers []*User `gorm:"many2many:user_sub_users.......` // no idea what to fill here
}
What's the gorm configuration I need to add to being able to retrieve the super users (parents) for one entity?
So, as an example, imagine that I have the following
Table users
| ID | name |
--------------=
| 1 | Alice |
| 2 | Bob |
| 3 | Joe |
| 4 | Manuel |
---------------
Table users_sub_users
| ID | user_id | sub_user_id |
-------------------------------
| 1 | 1 | 2 |
| 2 | 1 | 3 |
| 3 | 4 | 1 |
-------------------------------
So if I retrieve the user Alice, I want to get the following:
Alice ->
SubUsers: [Bob, Joe]
SuperUsers: [Manuel]
You can specify the fields in the table user_sub_users with joinForeignKey and joinReferences.
Instead of:
SubUsers []*User `gorm:"many2many:user_sub_users"`
it would be more explicit:
SubUsers []*User `gorm:"many2many:user_sub_users;joinForeignKey:sub_user_id;joinReferences:user_id;"`
For the SuperUsers just swap the fields:
SuperUsers []*User `gorm:"many2many:user_sub_users;joinForeignKey:user_id;joinReferences:sub_user_id;"`
Minimal example:
package main
import (
"fmt"
"github.com/glebarez/sqlite"
"gorm.io/gorm"
)
type User struct {
gorm.Model
Name string
SubUsers []*User `gorm:"many2many:user_sub_users;joinForeignKey:sub_user_id;joinReferences:user_id;"`
SuperUsers []*User `gorm:"many2many:user_sub_users;joinForeignKey:user_id;joinReferences:sub_user_id;"`
}
func main() {
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
panic(err)
}
db.AutoMigrate(&User{})
alice := &User{Name: "Alice"}
db.Create(alice)
bob := &User{Name: "Bob"}
db.Create(bob)
joe := &User{Name: "Joe"}
db.Create(joe)
manuel := &User{Name: "Manuel"}
db.Create(manuel)
err = db.Model(alice).Association("SubUsers").Append(bob, joe)
if err != nil {
panic(err)
}
err = db.Model(manuel).Association("SubUsers").Append(alice)
if err != nil {
panic(err)
}
var user User
err = db.Preload("SubUsers").Preload("SuperUsers").First(&user, alice.ID).Error
if err != nil {
panic(err)
}
for _, u := range user.SubUsers {
fmt.Println("Subuser", u.Name)
}
for _, u := range user.SuperUsers {
fmt.Println("Superuser", u.Name)
}
}

How to match keywords with pest?

I'm trying to parse a line like this
MyTupleComponent str, str
with grammar
cname = _{ (ASCII_ALPHANUMERIC | "_")+ }
ints = { "i8" | "i16" | "i32" | "i64" | "i128" | "isize" }
uints = { "u8" | "u16" | "u32" | "u64" | "u128" | "usize" }
strings = { "str" | "String" }
types = { strings | ints | uints }
tuple_component = { cname ~ (types ~ ("," ~ types)?)+ }
But end up with
Err(Error { variant: ParsingError { positives: [types], negatives: [] }, location: Pos(20), line_col: Pos((1, 21)), path: None, line: "MyTupleComponent str, str", continued_line: None })
Anyone know why the rule don't matches correctly?
You can take two roads:
As #ZachThompson pointed out, define WHITESPACE. If you do, make cname atomic, to prevent it from capturing alphanumerics AND spaces.
This test grammar seems fine:
WHITESPACE = _{ " " }
cname = #{ (ASCII_ALPHANUMERIC | "_")+ }
ints = { "i8" | "i16" | "i32" | "i64" | "i128" | "isize" }
uints = { "u8" | "u16" | "u32" | "u64" | "u128" | "usize" }
strings = { "str" | "String" }
types = { strings | ints | uints }
tuple_component = { cname ~ (types ~ ("," ~ types)?)+ }
file = { tuple_component ~ EOI }
Otherwise, you can account for spaces manually. This approach would work too, but it's not scalable with a growth of a grammar.
P.S. Is your intention to parse expressions like MyTupleComponent str, str str, str, without the comma to separate a second tuple from the first? It currently parses fine. You may want to simplify the rule to
tuple_component = { cname ~ types ~ ("," ~ types)* }

How to count number of times the primary key of a row is referenced in a specific table with Objection.js

(Using PostgreSQL)
So, I have these (User and Vote) Objection.js models:
const { Model } = require('objection');
class User extends Model {
static get tableName() {
return 'users';
}
static get relationMappings() {
return {
posts: {
relation: Model.HasManyRelation,
modelClass: require('./Post'),
join: {
from: 'users.id',
to: 'posts.userId',
},
},
comments: {
relation: Model.HasManyRelation,
modelClass: require('./Comment'),
join: {
from: 'users.id',
to: 'comments.userId'
}
},
votes: {
relation: Model.HasManyRelation,
modelClass: require('./Vote'),
join: {
from: 'users.id',
to: 'votes.userId'
}
}
};
}
}
module.exports = User;
const { Model } = require('objection');
class Vote extends Model {
static get tableName () { return 'votes' }
static get relationalMappings () {
return {
user: {
relation: Model.BelongsToOneRelation,
modelClass: require('./User'),
join: {
from: 'votes.userId',
to: 'users.id'
}
},
post: {
relation: Model.BelongsToOneRelation,
modelClass: require('./Post'),
join: {
from: 'votes.postId',
to: 'posts.id'
}
}
}
}
}
module.exports = Vote;
The psql command \d users returns:
Table "public.users"
Column | Type | Collation | Nullable | Default
-------------+------------------------+-----------+----------+-------------------
id | uuid | | not null | gen_random_uuid()
username | character varying(128) | | not null |
displayname | character varying(128) | | not null |
email | character varying(256) | | not null |
description | character varying(256) | | |
password | character varying(512) | | not null |
Indexes:
"users_pkey" PRIMARY KEY, btree (id)
"users_id_index" btree (id)
Referenced by:
TABLE "comments" CONSTRAINT "comments_userid_foreign" FOREIGN KEY ("userId") REFERENCES users(id)
TABLE "posts" CONSTRAINT "posts_userid_foreign" FOREIGN KEY ("userId") REFERENCES users(id)
TABLE "votes" CONSTRAINT "votes_userid_foreign" FOREIGN KEY ("userId") REFERENCES users(id)
And the psql command \d votes returns:
Table "public.votes"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+-------------------
id | uuid | | not null | gen_random_uuid()
userId | uuid | | not null |
postId | uuid | | not null |
up | boolean | | not null |
down | boolean | | not null |
Indexes:
"votes_pkey" PRIMARY KEY, btree (id)
"votes_id_index" btree (id)
Foreign-key constraints:
"votes_postid_foreign" FOREIGN KEY ("postId") REFERENCES posts(id)
"votes_userid_foreign" FOREIGN KEY ("userId") REFERENCES users(id)
What i would like to do is use some sort of Model class method (on the class User) to set the properties upvotes (number of Votes with up set to true), downvotes (number of Votes with down set to true) and balance (upvotes - downvotes).

How to generate a running sequence number in spark dataframe v1.6

I use spark v1.6. I have the below dataframe.
Primary_key | Dim_id
PK1 | 1
PK2 | 2
PK3 | 3
I would like to create a new dataframe with a new sequence #s whenever a new record comes in. Lets say, I get 2 new records from the source with values PK4 & PK5, I would like to create new dim_ids with the values 4 and 5. So, my new dataframe should look like below.
Primary_key | Dim_id
PK1 | 1
PK2 | 2
PK3 | 3
PK4 | 4
PK5 | 5
How to generate a running sequence number in spark dataframe v1.6 for the new records?
If you have a database somewhere, you can create a sequence in it, and use it with a user defined function (as you, I stumbled upon this problem...).
Reserve a bucket of sequence numbers, and use it (the incrementby parameter must be the same as the one used to create the sequence). As it's an object, SequenceID will be a singleton on each working node, and you can iterate over the bucket of sequences using the atomiclong.
It's far from being perfect (possible connection leaks, relies on a DB, locks on static class, does), comments welcome.
import java.sql.Connection
import java.sql.DriverManager
import java.util.concurrent.locks.ReentrantLock
import java.util.concurrent.atomic.AtomicLong
import org.apache.spark.sql.functions.udf
object SequenceID {
var current: AtomicLong = new AtomicLong
var max: Long = 0
var connection: Connection = null
var connectionLock = new ReentrantLock
var seqLock = new ReentrantLock
def getConnection(): Connection = {
if (connection != null) {
return connection
}
connectionLock.lock()
if (connection == null) {
// create your jdbc connection here
}
connectionLock.unlock()
connection
}
def next(sequence: String, incrementBy: Long): Long = {
if (current.get == max) {
// sequence bucket exhausted, get a new one
seqLock.lock()
if (current.get == max) {
val rs = getConnection().createStatement().executeQuery(s"SELECT NEXT VALUE FOR ${sequence} FROM sysibm.sysdummy1")
rs.next()
current.set(rs.getLong(1))
max = current.get + incrementBy
}
seqLock.unlock()
}
return current.getAndIncrement
}
}
class SequenceID() extends Serializable {
def next(sequence: String, incrementBy: Long): Long = {
return SequenceID.next(sequence, incrementBy)
}
}
val sequenceGenerator = new SequenceID(properties)
def sequenceUDF(seq: SequenceID) = udf[Long](() => {
seq.next("PK_SEQUENCE", 500L)
})
val seq = sequenceUDF(sequenceGenerator)
myDataframe.select(myDataframe("foo"), seq())

Syntax error on my Groovy script?

I am using GroovyShell (2.1.7) to dynamically evaluate some Groovy code that I have stored off as a string.
GroovyShell shell = magicallyInstantiateAndBindGroovyShell();
The above method takes care of instantiating the shell, and binding all the required variables to it. Since I believe this is a syntax error, I won't clutter this question with all the variables the shell is being bound with, and what the code I'm trying to evaluate is actually doing. If it turns out that I need to add any more info to the question to help solve my problem, I'll happily oblige!
I then have a string of Groovy code that I am trying to evaluate:
com.me.myorg.myapp.ExpressionUtils.metaClass.filterMetadata = {
com.me.myorg.myapp.model.WidgetVO widget, List<String> properties ->
WidgetVO toReturn = new WidgetVO();
toReturn.setFizz(widget.getFizz());
if(widget.getBuzz().equalsIgnoreCase("BIMDER")) {
toReturn.setMode(widget.getMode());
}
for(String property : properties) {
if("some.prop".equals(property)) {
Preconditions.checkNotNull(widget.getDescriptions());
toReturn.setDescriptions(new ArrayList<DescriptionVO>());
DescriptionVO description = widget.getDescriptions().get(0);
toReturn.getDescriptions().add(description);
} else if("another.prop".equals(property)) {
Preconditions.checkNotNull(widget.getTitles().get(0));
toReturn.setTitles(new ArrayList<TitleVO>());
TitleVO title = widget.getTitles().get(0);
toReturn.getTitles().add(title);
}
}
return toReturn;
};
Which I actually have stored off as a string variable:
String code = "com.me.myorg.myapp.ExpressionUtils.metaClass.filterMetadata = { com.me.myorg.myapp.model.WidgetVO widget, List<String> properties -> WidgetVO toReturn = new WidgetVO(); toReturn.setFizz(widget.getFizz()); if(widget.getBuzz().equalsIgnoreCase(\"BIMDER\")) { toReturn.setMode(widget.getMode()); } for(String property : properties) { if(\"some.prop\".equals(property)) { Preconditions.checkNotNull(widget.getDescriptions()); toReturn.setDescriptions(new ArrayList<DescriptionVO>()); DescriptionVO description = widget.getDescriptions().get(0); toReturn.getDescriptions().add(description); } else if(\"another.prop\".equals(property)) { Preconditions.checkNotNull(widget.getTitles().get(0)); toReturn.setTitles(new ArrayList<TitleVO>()); TitleVO title = widget.getTitles().get(0); toReturn.getTitles().add(title); } } return toReturn; };
When I run:
shell.evaluate(code);
I get the following exception:
startup failed, Script1.groovy: 1: unexpected token: for # line 1, column 294.
1 error
No signature of method: com.me.myorg.myapp.ExpressionUtils.metaClass.filterMetadata() is applicable for argument types: (com.me.myorg.myapp.model.WidgetVO, java.util.ArrayList) values: {com.me.myorg.myapp.model.WidgetVO#9427908c, ["some.prop", "another.prop"]}
Column 294 is the beginning of the for-loop... but to me, this seems like perfectly fine code. Am I forgetting a closing bracket anywhere? Some other syntax error? Where am I going awry? Thanks in advance!
You have:
if(widget.getBuzz().equalsIgnoreCase(\"BIMDER\")) { toReturn.setMode(widget.getMode()); } for(String property : properties)
You need a semicolon before the for...
Why not use a multi-line string?
String code = """com.me.myorg.myapp.ExpressionUtils.metaClass.filterMetadata = { com.me.myorg.myapp.model.WidgetVO widget, List<String> properties ->
| WidgetVO toReturn = new WidgetVO()
| toReturn.setFizz(widget.getFizz())
| if( widget.getBuzz().equalsIgnoreCase( "BIMDER" ) ) {
| toReturn.setMode(widget.getMode())
| }
| for( String property : properties ) {
| if( "some.prop" == property ) {
| Preconditions.checkNotNull( widget.descriptions )
| toReturn.descriptions = [ widget.descriptions[ 0 ] ]
| }
| else if( "another.prop" == property ) {
| Preconditions.checkNotNull( widget.titles[ 0 ] )
| toReturn.titles = [ widget.titles[ 0 ] ]
| }
| }
| toReturn
|}""".stripMargin()

Resources