-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(backend): add DB guards to projects policies migration
- Loading branch information
Showing
13 changed files
with
366 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 2 additions & 0 deletions
2
apps/backend/src/modules/projects-policies/elasticsearch/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './projects-policies-es-index.repo'; | ||
export * from './projects-policies-es-search.repo'; |
72 changes: 72 additions & 0 deletions
72
apps/backend/src/modules/projects-policies/elasticsearch/projects-policies-es-index.repo.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { array as A, taskEither as TE } from 'fp-ts'; | ||
import { pipe } from 'fp-ts/lib/function'; | ||
import snakecaseKeys from 'snakecase-keys'; | ||
import { inject, injectable } from 'tsyringe'; | ||
|
||
import { tryOrThrowTE } from '@llm/commons'; | ||
import { | ||
createBaseDatedRecordMappings, | ||
createElasticsearchIndexRepo, | ||
createIdObjectMapping, | ||
ElasticsearchRepo, | ||
type EsDocument, | ||
} from '~/modules/elasticsearch'; | ||
|
||
import type { ProjectPolicyTableRowWithRelations } from '../projects-policies.tables'; | ||
|
||
import { ProjectsPoliciesRepo } from '../projects-policies.repo'; | ||
|
||
const ProjectsPoliciesAbstractEsIndexRepo = createElasticsearchIndexRepo({ | ||
indexName: 'dashboard-projects-policies', | ||
schema: { | ||
mappings: { | ||
dynamic: false, | ||
properties: { | ||
...createBaseDatedRecordMappings(), | ||
project: createIdObjectMapping(), | ||
user: createIdObjectMapping(), | ||
group: createIdObjectMapping({ | ||
users: { | ||
type: 'nested', | ||
...createIdObjectMapping({ | ||
email: { type: 'keyword' }, | ||
}), | ||
}, | ||
}), | ||
}, | ||
}, | ||
settings: { | ||
'index.number_of_replicas': 1, | ||
}, | ||
}, | ||
}); | ||
|
||
export type ProjectsPoliciesEsDocument = EsDocument<ProjectPolicyTableRowWithRelations>; | ||
|
||
@injectable() | ||
export class ProjectsPoliciesEsIndexRepo extends ProjectsPoliciesAbstractEsIndexRepo<ProjectsPoliciesEsDocument> { | ||
constructor( | ||
@inject(ElasticsearchRepo) elasticsearchRepo: ElasticsearchRepo, | ||
@inject(ProjectsPoliciesRepo) private readonly policiesRepo: ProjectsPoliciesRepo, | ||
) { | ||
super(elasticsearchRepo); | ||
} | ||
|
||
protected async findEntities(ids: number[]): Promise<ProjectsPoliciesEsDocument[]> { | ||
return pipe( | ||
this.policiesRepo.findWithRelationsByIds({ ids }), | ||
TE.map( | ||
A.map(entity => ({ | ||
...snakecaseKeys(entity, { deep: true }), | ||
_id: String(entity.id), | ||
})), | ||
), | ||
tryOrThrowTE, | ||
)(); | ||
} | ||
|
||
protected createAllEntitiesIdsIterator = () => | ||
this.policiesRepo.createIdsIterator({ | ||
chunkSize: 100, | ||
}); | ||
} |
59 changes: 59 additions & 0 deletions
59
apps/backend/src/modules/projects-policies/elasticsearch/projects-policies-es-search.repo.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import esb from 'elastic-builder'; | ||
import { taskEither as TE } from 'fp-ts'; | ||
import { pipe } from 'fp-ts/lib/function'; | ||
import { inject, injectable } from 'tsyringe'; | ||
|
||
import type { SdkProjectPolicyT } from '@llm/sdk'; | ||
import type { TableId } from '~/modules/database'; | ||
|
||
import { tryGetFirstRawResponseHitOrNotExists } from '~/modules/elasticsearch/helpers'; | ||
|
||
import { | ||
type ProjectsPoliciesEsDocument, | ||
ProjectsPoliciesEsIndexRepo, | ||
} from './projects-policies-es-index.repo'; | ||
|
||
@injectable() | ||
export class ProjectsPoliciesEsSearchRepo { | ||
constructor( | ||
@inject(ProjectsPoliciesEsIndexRepo) private readonly indexRepo: ProjectsPoliciesEsIndexRepo, | ||
) {} | ||
|
||
getByProjectId = (projectId: TableId) => pipe( | ||
this.indexRepo.search( | ||
esb | ||
.requestBodySearch() | ||
.query( | ||
esb | ||
.boolQuery() | ||
.must(esb.termQuery('project.id', projectId)), | ||
) | ||
.toJSON(), | ||
), | ||
tryGetFirstRawResponseHitOrNotExists, | ||
TE.map(doc => ProjectsPoliciesEsSearchRepo.mapOutputHit(doc._source as ProjectsPoliciesEsDocument)), | ||
); | ||
|
||
private static mapOutputHit = (source: ProjectsPoliciesEsDocument): SdkProjectPolicyT => { | ||
const record = { | ||
id: source.id, | ||
createdAt: source.created_at, | ||
updatedAt: source.updated_at, | ||
project: source.project, | ||
user: null, | ||
group: null, | ||
}; | ||
|
||
if (source.user) { | ||
return { | ||
...record, | ||
user: source.user, | ||
}; | ||
} | ||
|
||
return { | ||
...record, | ||
group: source.group!, | ||
}; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,4 @@ | ||
export * from './elasticsearch'; | ||
export * from './projects-policies.repo'; | ||
export * from './projects-policies.service'; | ||
export * from './projects-policies.tables'; |
90 changes: 90 additions & 0 deletions
90
apps/backend/src/modules/projects-policies/projects-policies.repo.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import { array as A, option as O, taskEither as TE } from 'fp-ts'; | ||
import { pipe } from 'fp-ts/lib/function'; | ||
import { injectable } from 'tsyringe'; | ||
|
||
import { | ||
createDatabaseRepo, | ||
DatabaseError, | ||
type TableId, | ||
type TransactionalAttrs, | ||
tryReuseTransactionOrSkip, | ||
} from '../database'; | ||
import { ProjectPolicyTableRowWithRelations } from './projects-policies.tables'; | ||
|
||
@injectable() | ||
export class ProjectsPoliciesRepo extends createDatabaseRepo('projects_policies') { | ||
findWithRelationsByIds = ({ forwardTransaction, ids }: TransactionalAttrs<{ ids: TableId[]; }>) => { | ||
const transaction = tryReuseTransactionOrSkip({ db: this.db, forwardTransaction }); | ||
|
||
return pipe( | ||
transaction( | ||
async qb => | ||
qb | ||
.selectFrom(this.table) | ||
.where('projects_policies.id', 'in', ids) | ||
.innerJoin('projects', 'projects.id', 'project_id') | ||
|
||
.leftJoin('users', 'users.id', 'user_id') | ||
.leftJoin('users_groups', 'users_groups.id', 'group_id') | ||
|
||
.selectAll('projects_policies') | ||
.select([ | ||
'user_id as user_id', | ||
'users.email as user_email', | ||
|
||
'group_id as group_id', | ||
'users_groups.name as group_name', | ||
|
||
'projects.id as project_id', | ||
'projects.name as project_name', | ||
]) | ||
.limit(ids.length) | ||
.execute(), | ||
), | ||
DatabaseError.tryTask, | ||
TE.map( | ||
A.filterMap(({ | ||
project_id: projectId, | ||
project_name: projectName, | ||
|
||
user_id: userId, | ||
user_email: userEmail, | ||
|
||
group_id: groupId, | ||
group_name: groupName, | ||
|
||
...item | ||
}): O.Option<ProjectPolicyTableRowWithRelations> => { | ||
const record = { | ||
id: item.id, | ||
createdAt: item.created_at, | ||
updatedAt: item.updated_at, | ||
accessLevel: item.access_level, | ||
group: null, | ||
user: null, | ||
project: { | ||
id: projectId, | ||
name: projectName, | ||
}, | ||
}; | ||
|
||
if (groupId) { | ||
return O.some({ | ||
...record, | ||
group: { id: groupId, name: groupName!, users: [] }, | ||
}); | ||
} | ||
|
||
if (userId) { | ||
return O.some({ | ||
...record, | ||
user: { id: userId, email: userEmail! }, | ||
}); | ||
} | ||
|
||
return O.none; | ||
}), | ||
), | ||
); | ||
}; | ||
} |
12 changes: 12 additions & 0 deletions
12
apps/backend/src/modules/projects-policies/projects-policies.service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { inject, injectable } from 'tsyringe'; | ||
|
||
import { ProjectsPoliciesEsSearchRepo } from './elasticsearch'; | ||
|
||
@injectable() | ||
export class ProjectsPoliciesService { | ||
constructor( | ||
@inject(ProjectsPoliciesEsSearchRepo) private readonly esSearchRepo: ProjectsPoliciesEsSearchRepo, | ||
) {} | ||
|
||
getByProjectId = this.esSearchRepo.getByProjectId; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
export * from './users-groups.repo'; | ||
export * from './users-groups.tables'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { injectable } from 'tsyringe'; | ||
|
||
import { createDatabaseRepo } from '../database'; | ||
|
||
@injectable() | ||
export class UsersGroupsRepo extends createDatabaseRepo('users_groups') {} |
1 change: 1 addition & 0 deletions
1
packages/sdk/src/modules/dashboard/projects-policies/dto/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
export * from './sdk-project-access-level.dto'; | ||
export * from './sdk-project-policy.dto'; |
Oops, something went wrong.