I prepared view in my PostgresDB called user_details. I created UserDetail entity and UserDetailRepository. Here you have shortened version of my view to visualize my problem:
CREATE VIEW user_details AS
SELECT id, user_name FROM users WHERE user_name like '$1#%'
My question is how to inject parameter using Hanami repository?
I can use raw sql in my repos which is described here http://hanamirb.org/guides/models/repositories/ but I prefer to create view in postgres using migrations. I don't want to improve query but to know if I can user parameterized queries with Hanami. Thanks for all answers
PostgreSQL doesn't support parameterized views in the way you described. It can have views that call a function which in order can access the current session state and you can set that state just before selecting data from the view. However, I'd recommend you define a method with an argument instead
class UserRepo
def user_details(prefix)
root.project { [id, user_name] }.where { user_name.ilike("#{ prefix }%") }.to_a
end
end
What you get with this is basically the same. If you want to use user_details as a base relation you can define a private method on the repo and call it from other public methods
class UserRepo
def user_details_filtered(user_name, min_user_id = 0)
user_details(prefix).where { id > min_user_id }.to_a
end
def user_details_created_after(user_name, after)
user_details(prefix).where { created_at > after }.to_a
end
private
# Don't call this method from the app code, this way
# you don't leak SQL-specific code into your domain
def user_details(prefix)
root.project { [id, user_name] }.where { user_name.ilike("#{ prefix }%") }
end
end
Related
I'm learning GraphQL by building a simple python application, basically runs nmap scans stores output to a database, and can be queried by a GraphQL API. I seem to be a bit confused on how GraphQL works.
I have a few tables that are one-to-many relationships: user has many scans, scans have results, results have hosts, hosts have ports, hosts have os. Which I defined using sqlalchemy and used graphene
Now, in my GraphQL schema I have:
class Scans(SQLAlchemyObjectType):
class Meta:
model = ScansModel
class ScanResult(SQLAlchemyObjectType):
class Meta:
model = ScanResultModel
class Hosts(SQLAlchemyObjectType):
class Meta:
model = HostInfoModel
class Ports(SQLAlchemyObjectType):
class Meta:
model = PortInfoModel
class Os(SQLAlchemyObjectType):
class Meta:
model = OsInfoModel
class Query(graphene.ObjectType):
user = graphene.Field(User)
scans = graphene.List(Scans)
scan_results = graphene.List(ScanResult)
hosts = graphene.List(Hosts)
ports = graphene.List(Ports)
os = graphene.Field(Os)
def resolve_scans(self, info):
query = Scans.get_query(info)
return query
Now, when I make a GraphQL query, I can query scans, results, hostinfo, portinfo, osinfo, without having to have resolvers for those fields. I was under the impression that each of those fields would need a resolver.
Furthermore, I seem to be able to do circular quereis (so from scanresults I can query scans and from scans I can query user) due to the foreign keys and relationship table.
Is this the correct behaviour, or am misunderstanding how GraphQL works?
What you need to do is:
class ScanResult(SQLAlchemyObjectType):
class Meta:
model = ScanResultModel
scans = graphene.List(Scans, description="Scans from results.")
def resolve_scans(self, info):
query = Scans.get_query(info)
return query.filter(ScansModel.my_id == self.scans_id).all()
This will probably enables you to build queries like:
{
scanresult{
edges {
node {
id
scans{
id
}
}
}
}
I know that resolvers for each field with SQLAlchemyObjecType are handled inside the library.
when I use mongoengine without using MongoengineObjectType, I code like this.
class Query(graphene.ObjectType):
department = graphene.List(of_type=DepartmentField,
name=graphene.String(default_value="all"))
role = graphene.List(of_type=RoleField,
name=graphene.String(default_value="all"))
employee = graphene.List(of_type=EmployeeField,
name=graphene.String(default_value="all"))
def resolve_department(self, info, name):
if name == "all":
department = [construct(DepartmentField, object) for object in DepartmentModel.objects]
return department
else:
department = DepartmentModel.objects.get(name=name)
return [construct(DepartmentField, department)]
def resolve_role(self, info, name):
.
.
.
I am writing a single sign on plugin for SonarQube.
All my user information are located in the UserPrincipal of the HttpRequest (not the password ;-) ).
For the moment, I can sign on and provide the UserDetails to Sonar through the method
public UserDetails doGetUserDetails(Context context);
Now I would like to provide the groups of the user to SonarQube but the method
public Collection<String> doGetGroups(String username)
does not provide the context.
To solve my issue, I have modified the code of need_authentication.rb of Sonar (located in sonarqube-4.4\web\WEB-INF\lib)
to call a method
public Collection<String> doGetGroups(String username, HttpServletRequest)
I have written.
But I don't like modyfing source code; I would prefer overide it by extending the class PluginRealm of the file need_authentication.rb.
Basically, how do I extend a class in SonarQube ?
I know how to overide a controller but not class located in lib folder.
Also (I don't know Ruby at all).
Thank you for your help
SONAR-5430 will allow to natively implement such a feature.
For people who cannot use the solution of Fabrice, here is what I did until the new feature is released.
I create a controller in ruby I add to my plugin realm.
This controller extends ApplicationController controller.
It redefines authenticate method wich calls the default method of Sonar
def authenticate
begin
self.current_user = User.authenticate(nil, nil, servlet_request)
if self.current_user
my_synchronize_groups(servlet_request)
end
rescue Exception => e
self.current_user = nil
Rails.logger.error(e.message)
end
redirect_back_or_default(home_url)
end
When you use a User.authenticate(nil, nil, servlet_request) it calls the synchronize_groups(user) in need_authorization.rb and synchronize the groups.
What I do is calling my_synchronize_groups after User.authenticate(nil, nil, servlet_request) to override the groups synchronization done by sonar.
Here is the code of my_synchronize_groups
def my_synchronize_groups(servlet_request)
Rails.logger.debug("My synchronize_groups method")
myRealm = RealmFactory.realm
Rails.logger.debug("My realm #{myRealm}")
if myRealm
myGroupsProvider = myRealm.instance_variable_get(:#java_groups_provider)
Rails.logger.debug("My group provider #{myGroupsProvider}")
if myGroupsProvider
begin
groups = myGroupsProvider.doGetGroups(servlet_request)
rescue Exception => e
Rails.logger.error("Error from my groups provider: #{e.message}")
else
if groups
self.current_user.groups = []
for group_name in groups
group = Group.find_by_name(group_name)
if group
self.current_user.groups << group
end
end
end
end
end
end
end
The method myGroupsProvider.doGetGroups(servlet_request) is a method located in MyGroupsProvider.java which extends ExternalGroupsProvider.java and return a collection of String.
I am not saying it is the best solution but with my knowledge of Ruby ...
Hoping it can help
Simon
My team is using Entity Framework 4.3.0 - Code Only with POCO classes as our ORM. Right now we use DBSets of Classes to access our 'tables'
Public Property Customers As DbSet(Of Customers)
But often we are doing soft deletes based on a IsDeleted column in LINQ, and filtering our select statements accordingly:
Dim LiveCustomers =
From C In EM.Customers
Where C.DeleteFlag = False
What I would really like to do is, instead of writing every query to include this filter, create some lower level property (possibly at our inherited DbContext level) that provides the filtered set, while maintaining strong type.
I tried this:
Public Property Customers As DbSet(Of Customer)
Public Property Customers_Live As DbSet(Of Customer)
Get
Return From C In Customers
Where C.DeleteFlag = False
End Get
Set(value As DbSet(Of Customer))
Customers = value
End Set
End Property
However that yielded me this error:
Multiple object sets per type are not supported. The object sets 'Customers' and 'Customers_Live' can both contain instances of type '__.Customer'.
A quick check on google yielded this promising result (How to: Query Objects with Multiple Entity Sets per Type) But after updating my Connection String, I'm still getting the same error.
<add name="EntityManager"
providerName="System.Data.SqlClient"
connectionString="
Data Source=xxxxxx;
Initial Catalog=xxxxxx;
User Id=xxxxxx;
Password=xxxxxx;
MultipleActiveResultSets=True"/>
So my question is, how could I effectively create a LINQ view that allows me to apply filtering, without impacting the upstream usage too drastically?
Change your property like this:
Public Property Customers As DbSet(Of Customer)
Public Property Customers_Live As IQueryable(Of Customer)
Get
Return From C In Customers
Where C.DeleteFlag = False
End Get
End Property
This is slightly different, as you won't have things like Add() or Remove(), but for a view you typically wouldn't expect to have that kind of functionality. If you want to add a new one, or remove one you should use the normal Customers property.
You could have your POCO classes inherit from a new class that has a new method that would do the filtering for you. Add something like this to the new class
--PSEUDO CODE!--
Public Function Filtered() as IEnumerable(Of Out T)
Return (From x In Me Where x.DeleteFlag).ToList()
End Function
and you could call it like:
Dim LiveCustomers =
From C In EM.Customers.Filtered
Or you could create an Interface and do a dependancy injection when you call your linq query. You'll have to google that one :)
I am implementing ACL security using the spring-security-acl plugin. I have the following domain classes:
package test
class Subitem {
String name
static belongsTo = [employer: Employer]
static constraints = {
name blank: false
}
}
package test
class Employer {
String name
static hasMany = [users: User, items: Subitem]
static belongsTo = User
static constraints = {
name blank: false, unique: true
}
String toString() {
name
}
}
In the create.gsp file which is used to create a Subitem, there is the following statement:
<g:select id="employer" name="employer.id" from="${test.Employer.list()}" optionKey="id" required="" value="${subitemInstance?.employer?.id}" class="many-to-one"/>
From the EmployerController:
def list = {
params.max = Math.min(params.max ? params.int('max') : 10, 100)
[employerInstanceList: employerService.list(params),
employerInstanceTotal: employerService.count()]
}
Following the tutorial given here, I have moved some of the functionality with dealing with Employer to a service called EmployerService:
#PreAuthorize("hasRole('ROLE_USER')")
#PostFilter("hasPermission(filterObject, read)")
List<Employer> list(Map params) {
Employer.list params
}
int count() {
Employer.count()
}
Access to information in any given Employer class instance is restricted using ACL. At present, I can see ALL instances of Employer in the database in the drop down, and I assume that is because I am using the controller list(), not the service list() - however, I only want to see the filtered list of Employer domain classes. However, if I replace the g:select with:
<g:select id="employer" name="employer.id" from="${test.EmployerService.list()}" optionKey="id" required="" value="${subitemInstance?.employer?.id}" class="many-to-one"/>
then I get an internal server error because I haven't passed a Map parameter to the service list() function (and I don't know how to do this within the tag):
URI /security/subitem/create
Class groovy.lang.MissingMethodException
Message No signature of method: static test.EmployerService.list() is applicable for argument types: () values: [] Possible solutions: list(java.util.Map), is(java.lang.Object), wait(), find(), wait(long), get(long)
I only want to see the information that comes from the EmployerService list() function - how do I do this please? How do I reference the correct function from within the gap?
Edit 16 Mar 0835: Thanks #OverZealous, that's really helpful, I hadn't realised that. However, I've tried that and still get the same problem. I've put a println() statement in both the Employer and EmployerService list() functions, and can see that neither actually seems to get called when the g:select tag is parsed (even if I leave the g:select to refer to Employer). Is there another version of the list() function that is being called perhaps? Or how else to get the g:select to take account of the ACL?
Just change your method signature in the Service to look like this:
List<Employer> list(Map params = [:]) {
Employer.list params
}
The change is adding this: = [:]. This provides a default value for params, in this case, an empty map.
(This is a Groovy feature, BTW. You can use it on any method or closure where the arguments are optional, and you want to provide a default.)
OK, I worked it out, and here is the solution to anyone else who comes up against the same problem.
The create Subitem page is rendered by means of the Subitem's create.gsp file and the SubitemController. The trick is to amend the SubitemController create() closure:
class SubitemController {
def employerService
def create() {
// this line was the default supplied method:
// [subitemInstance: new Subitem(params)]
// so replace with the following:
params.max = Math.min(params.max ? params.int('max') : 10, 100)
[subitemInstance: new Subitem(params), employerInstanceList: employerService.list(params),
employerInstanceTotal: employerService.count()]
}
}
So now when the SubitemController is asked by the g:select within the Subitem view for the list of Employers, it calls the EmployerService, which supplies the correct answer. We have simply added 2 further variables that are returned to the view, and which can be referenced anywhere within the view (such as by the g:select tag).
The lesson for me is that the View interacts with the Controller, which can refer to a Service: the Service doesn't play nicely with a View, it seems.
I am trying to extend my Linq-to-Sql entity with a few extra properties. These are "calculated" properties based on data from the underlying SQL View. For example, think of having a Date of Birth field, which is used to calculate an extended Age field.
I tried to extend my entity class by extending the OnLoaded() method.
I get a compile time error however stating that I cannot create it. I checked the designer code for my LTS entity class, and it doesn't have a partial definition for any of the expected extension points.
I checked a few of my other LTS entity classes and they do have these extension points. The only difference I see is that the one without is loaded from a SQL View, rather than a table. Is there a way to hook into a "Loaded" event when loading from a SQL View?
TIA!
I found that I did not have a PrimaryKey specified for my Linq-to-Sql entity class. I believe without a Primary Key specified, no extension methods generated in the entity class. Once I specified a Primary Key on my LTS entity class definition (through the designer), I was able to extend the OnLoaded() event.
You can do this by means of a property. Just create a partial class with the same name as your entity. Any properties or methods that you add will automatically be part of the entity and allow to use any of its members.
Here's an example of the pattern:
public partial class [The Name of the Entity]
{
public int Age
{
get
{
return CalculateAge(this.DateOfBirth);
}
}
}
Here's some logic on how to calculate the Age (Source: Geekpedia)
public static int CalculateAge(DateTime BirthDate)
{
int YearsPassed = DateTime.Now.Year - BirthDate.Year;
// Are we before the birth date this year? If so subtract one year from the mix
if (DateTime.Now.Month < BirthDate.Month ||
(DateTime.Now.Month == BirthDate.Month && DateTime.Now.Day < BirthDate.Day))
{
YearsPassed--;
}
return YearsPassed;
}