Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
802a524
feat(relation): add new relation decorator
matthv Jan 25, 2024
dc91d7b
feat(customizer): add new methods to handle relation
matthv Jan 25, 2024
58fbd51
feat: add sort utils
matthv Jan 26, 2024
367be5c
chore: add new sort validator
matthv Jan 26, 2024
a6d9ee0
chore: add parse_sort method on query_string_parser
matthv Jan 26, 2024
200bd16
fix: parse_sort on query_string_parser
matthv Jan 29, 2024
71b5f1f
chore: add sort test on query_string_parser
matthv Jan 29, 2024
752be9c
fix: sort and add some tests
matthv Jan 29, 2024
beb4b48
chore: add tests on sort_validator
matthv Jan 29, 2024
4d849a5
fix: sort_factory module
matthv Jan 29, 2024
c84befe
fix(sort): apply function
nicolasalexandre9 Jan 30, 2024
4f7210e
fix: record utils
matthv Jan 30, 2024
167b656
chore: add test on sort_factory
matthv Jan 30, 2024
d33b236
fix: sort
matthv Jan 30, 2024
a7894ec
chore: remove useless comment
matthv Jan 30, 2024
deea264
feat(decorator): add new relation decorator
matthv Jan 30, 2024
e1c9791
fix: relationdecorator
matthv Feb 1, 2024
db83911
fix: permission & context_variables
matthv Feb 13, 2024
bb960ba
fix: context_variable_injector test
matthv Feb 13, 2024
6ea9418
chore: projection add apply method and utils for Hash
matthv Feb 14, 2024
cd9c07d
chore: add missing test on Projection
matthv Feb 14, 2024
7309024
fix: condition tree leaf
matthv Feb 15, 2024
1d15abb
fix: record utils
matthv Feb 15, 2024
9c578d2
chore: projection add union method
matthv Feb 15, 2024
a2efeee
chore: add test on relation decorator
matthv Feb 15, 2024
dbe8de7
fix: utils and relation decorator
matthv Feb 27, 2024
a2acdff
fix: test on relation decorator
matthv Feb 28, 2024
9316ae9
feat(relation): add external relation plugin
matthv Feb 29, 2024
208934a
chore: add tests on collection_customizer
matthv Feb 29, 2024
ed99521
fix: test
matthv Feb 29, 2024
f2e789c
fix: import schema utils
matthv Feb 29, 2024
e0f05b4
fix: tests
matthv Mar 1, 2024
c541ae0
fix: sort & projection replace methods
matthv Mar 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .rubocop.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -229,6 +229,7 @@ Metrics/ClassLength:
- 'packages/forest_admin_agent/lib/forest_admin_agent/services/permissions.rb'
- 'packages/forest_admin_agent/lib/forest_admin_agent/routes/charts/charts.rb'
- 'packages/forest_admin_agent/lib/forest_admin_agent/routes/action/action.rb'
- 'packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/decorators/relation/relation_collection_decorator.rb'
- 'packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/utils/collection.rb'
- 'packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/components/query/aggregation.rb'
- 'packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/components/query/filter_factory.rb'
Expand DownExpand Up@@ -259,6 +260,7 @@ Layout/LineLength:
- 'packages/forest_admin_agent/lib/forest_admin_agent/http/forest_admin_api_requester.rb'
- 'packages/forest_admin_agent/lib/forest_admin_agent/routes/resources/list.rb'
- 'packages/forest_admin_agent/lib/forest_admin_agent/services/permissions.rb'
- 'packages/forest_admin_datasource_customizer/lib/forest_admin_datasource_customizer/decorators/relation/relation_collection_decorator.rb'
- 'packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/components/query/condition_tree/condition_tree_factory.rb'
- 'packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/utils/collection.rb'
- 'packages/forest_admin_datasource_toolkit/lib/forest_admin_datasource_toolkit/components/query/filter_factory.rb'
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -103,6 +103,9 @@ def get_scope(collection)

return nil if scope.nil?

team = get_team(caller.rendering_id)
user = get_user_data(caller.id)

context_variables = ContextVariables.new(team, user)

ContextVariablesInjector.inject_context_in_filter(scope, context_variables)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -29,7 +29,10 @@ def get_current_user_data(context_variable_key)
end

if context_variable_key.start_with?(USER_VALUE_TAG_PREFIX)
return user[:tags][context_variable_key[USER_VALUE_TAG_PREFIX.length..]]
user[:tags].each do |tag|
match_key = context_variable_key[USER_VALUE_TAG_PREFIX.length..]
return tag[match_key] if tag.key?(match_key)
end
end

user[context_variable_key[USER_VALUE_PREFIX.length..].to_sym]
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -104,6 +104,18 @@ def self.parse_search_extended(args)

extended != '0'
end

def self.parse_sort(collection, args)
sort_string = args.dig(:params, :sort)

return SortUtils::SortFactory.by_primary_keys(collection) unless sort_string

sort = Sort.new([
{ field: sort_string.gsub(/^-/, '').tr('.', ':'), ascending: !sort_string.start_with?('-') }
])

ForestAdminDatasourceToolkit::Validations::SortValidator.validate(collection, sort)
end
end
end
end
Original file line numberDiff line numberDiff line change
Expand Up@@ -12,7 +12,7 @@ module Utils
'lastName' => 'Doe',
'fullName' => 'John Doe',
'email' => 'john.doe@domain.com',
'tags' => { 'planet' => 'Death Star' },
'tags' => [{ 'planet' => 'Death Star' }],
'roleId' => 1,
'permissionLevel' => 'admin'
}
Expand DownExpand Up@@ -89,7 +89,7 @@ module Utils
{ key: 'id', expected_value: user['id'] },
{ key: 'permissionLevel', expected_value: user['permissionLevel'] },
{ key: 'roleId', expected_value: user['roleId'] },
{ key: 'tags.planet', expected_value: user['tags']['planet'] },
{ key: 'tags.planet', expected_value: user['tags'][0]['planet'] },
{ key: 'team.id', expected_value: team['id'] },
{ key: 'team.name', expected_value: team['name'] }
].each do |value|
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,7 +10,7 @@ module Utils
lastName: 'Doe',
fullName: 'John Doe',
email: 'johndoe@forestadmin.com',
tags: { 'foo' => 'bar' },
tags: [{ 'foo' => 'bar' }],
roleId: 1,
permissionLevel: 'admin'
}
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -439,6 +439,57 @@ module Utils
expect(described_class.parse_search_extended(args)).to be(false)
end
end

describe 'parse_sort' do
let(:collection_user) do
datasource = Datasource.new
collection_user = Collection.new(datasource, 'User')
collection_user.add_fields(
{
'id' => ColumnSchema.new(column_type: 'Number', is_primary_key: true,
filter_operators: [Operators::EQUAL]),
'name' => ColumnSchema.new(column_type: 'String')
}
)

datasource.add_collection(collection_user)

return collection_user
end

it 'sorts by pk ascending when not sort is given' do
args = {
params: {}
}

expect(described_class.parse_sort(collection_user, args)).to eq([{ field: 'id', ascending: true }])
end

it 'sorts by the request field and order when given' do
args = {
params: {
sort: '-name'
}
}

expect(described_class.parse_sort(collection_user, args)).to eq([{ field: 'name', ascending: false }])
end

it 'throws a ValidationError when the requested sort is invalid' do
args = {
params: {
sort: '-fieldThatDoNotExist'
}
}

expect do
described_class.parse_sort(collection_user, args)
end.to raise_error(
ForestAdminDatasourceToolkit::Exceptions::ForestException,
"🌳🌳🌳 Column not found: 'User.fieldThatDoNotExist'"
)
end
end
end
end
end
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,12 +22,6 @@ def collection
@stack.datasource.get_collection(@name)
end

def use(plugin, options = [])
push_customization(
proc { plugin.run(@datasource_customizer, self, options) }
)
end

def disable_count
push_customization(
-> { @stack.schema.get_collection(@name).override_schema(countable: false) }
Expand DownExpand Up@@ -58,10 +52,93 @@ def add_field(name, definition)
)
end

# Add a many to one relation to the collection
# @param name name of the new relation
# @param foreign_collection name of the targeted collection
# @param options extra information about the relation
# @example
# books.add_many_to_one_relation('my_author', 'persons', { foreign_key: 'author_id' })
def add_many_to_one_relation(name, foreign_collection, options = {})
push_relation(name, {
type: 'ManyToOne',
foreign_collection: foreign_collection,
foreign_key: options[:foreign_key],
foreign_key_target: options[:foreign_key_target]
})
end

# Add a one to many relation to the collection
# @param name name of the new relation
# @param foreign_collection name of the targeted collection
# @param options extra information about the relation
# @example
# persons.add_one_to_many_relation('written_books', 'books', { origin_key: 'author_id' })
def add_one_to_many_relation(name, foreign_collection, options = {})
push_relation(name, {
type: 'OneToMany',
foreign_collection: foreign_collection,
origin_key: options[:origin_key],
origin_key_target: options[:origin_key_target]
})
end

# Add a one to one relation to the collection
# @param name name of the new relation
# @param foreign_collection name of the targeted collection
# @param options extra information about the relation
# @example
# persons.add_one_to_one_relation('best_friend', 'persons', { origin_key: 'best_friend_id' })
def add_one_to_one_relation(name, foreign_collection, options = {})
push_relation(name, {
type: 'OneToOne',
foreign_collection: foreign_collection,
origin_key: options[:origin_key],
origin_key_target: options[:origin_key_target]
})
end

# Add a many to many relation to the collection
# @param name name of the new relation
# @param foreign_collection name of the targeted collection
# @param through_collection name of the intermediary collection
# @param options extra information about the relation
# @example
# dvds.add_many_to_many_relation('rentals_of_this_dvd', 'rentals', 'dvd_rentals', {
# origin_key: 'dvd_id',
# foreign_key: 'rental_id'
# })
def add_many_to_many_relation(name, foreign_collection, through_collection, options = {})
push_relation(name, {
type: 'ManyToMany',
foreign_collection: foreign_collection,
through_collection: through_collection,
origin_key: options[:origin_key],
origin_key_target: options[:origin_key_target],
foreign_key: options[:foreign_key],
foreign_key_target: options[:foreign_key_target]
})
end

def use(plugin, options = [])
push_customization(
proc { plugin.new.run(@datasource_customizer, self, options) }
)
end

def add_external_relation(name, definition)
use(ForestAdminDatasourceCustomizer::Plugins::AddExternalRelation, { name: name }.merge(definition))
end

private

def push_customization(customization)
@stack.queue_customization(customization)
end

def push_relation(name, definition)
push_customization(
proc { @stack.relation.get_collection(@name).add_relation(name, definition) }
)
end
end
end
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@ module Decorators
class DecoratorsStack
include ForestAdminDatasourceToolkit::Decorators

attr_reader :datasource, :schema, :search, :early_computed, :late_computed, :action
attr_reader :datasource, :schema, :search, :early_computed, :late_computed, :action, :relation

def initialize(datasource)
@customizations = []
Expand All@@ -12,7 +12,10 @@ def initialize(datasource)
last = DatasourceDecorator.new(last, Empty::EmptyCollectionDecorator)
last = DatasourceDecorator.new(last, OperatorsEquivalence::OperatorsEquivalenceCollectionDecorator)
last = @early_computed = DatasourceDecorator.new(last, Computed::ComputeCollectionDecorator)
last = DatasourceDecorator.new(last, OperatorsEquivalence::OperatorsEquivalenceCollectionDecorator)
last = @relation = DatasourceDecorator.new(last, Relation::RelationCollectionDecorator)
last = @late_computed = DatasourceDecorator.new(last, Computed::ComputeCollectionDecorator)
last = DatasourceDecorator.new(last, OperatorsEquivalence::OperatorsEquivalenceCollectionDecorator)
last = @search = DatasourceDecorator.new(last, Search::SearchCollectionDecorator)
last = @action = DatasourceDecorator.new(last, Action::ActionCollectionDecorator)
last = @schema = DatasourceDecorator.new(last, Schema::SchemaCollectionDecorator)
Expand Down
Loading