loopbackio / loopbackio/loopback-next

[@loopback/sequelize] syncSequelizeModel error for models having property type array & item-type object

オープン
#10,443 コメント 3 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

bug
主要言語
TypeScript
スター
5.1k
フォーク
1.1k
平均マージ
2日 21時間
マージ済み PR(30日)
27

説明

Describe the bug

Everything was working fine in old versions 0.5.2 but after upgrading 0.6.0 facing issues,
This started after this code :

image

in this PR :

https://github.com/loopbackio/loopback-next/pull/10284/files#diff-eed487b3bfde7c98474b321fa2c69aeea23caff62901d6b710ef7c44517ff328

My model has this property :

@property({
type: 'array',
itemType: 'object',
name: 'patientPresenterOrgs',
description:
'Organizations associated with the user as patient presenters.',
})
patientPresenterOrgs?: PatientPresenterOrg[];

Error :

"SQLITE_ERROR: near "[]": syntax error"

"Error: \n at Database. (/Users/vaibhav.kumar/Documents/projects/telescope/telescope-health-backend-api/node_modules/sequelize/src/dialects/sqlite/query.js:236:27)\n at /Users/vaibhav.kumar/Documents/projects/telescope/telescope-health-backend-api/node_modules/sequelize/src/dialects/sqlite/query.js:234:50\n at new Promise ()\n at Query.run (/Users/vaibhav.kumar/Documents/projects/telescope/telescope-health-backend-api/node_modules/sequelize/src/dialects/sqlite/query.js:234:12)\n at /Users/vaibhav.kumar/Documents/projects/telescope/telescope-health-backend-api/node_modules/sequelize/src/sequelize.js:650:28\n at SQLiteQueryInterface.createTable (/Users/vaibhav.kumar/Documents/projects/telescope/telescope-health-backend-api/node_modules/sequelize/src/dialects/abstract/query-interface.js:229:12)\n at Function.sync (/Users/vaibhav.kumar/Documents/projects/telescope/telescope-health-backend-api/node_modules/sequelize/src/model.js:1353:7)\n at UserViewRepository.syncSequelizeModel (/Users/vaibhav.kumar/Documents/projects/telescope/telescope-health-backend-api/node_modules/@loopback/sequelize/src/sequelize/sequelize.repository.base.ts:861:5)\n at async Promise.all (index 1)\n at Context. (/Users/vaibhav.kumar/Documents/projects/telescope/telescope-health-backend-api/services/snap-md-service/src/tests/acceptance/encounter-helper.controller.acceptance.ts:34:5)"

Error is in this line :

beforeEach('run before every test case', async () => {
await Promise.all(
allRepos
.map(rep => rep.syncSequelizeModel({force: true}))
.filter(Boolean),
);
});

This is complete error reason :

{ name: "SequelizeDatabaseError", parent: { errno: 1, code: "SQLITE_ERROR", sql: "CREATE TABLE IF NOT EXISTS v_users (deletedTINYINT(1) DEFAULT 0,deleted_onDATETIME,deleted_byVARCHAR(255),created_onDATETIME,modified_onDATETIME,created_byVARCHAR(255),modified_byVARCHAR(255),suffixVARCHAR(255),first_nameVARCHAR(255),last_nameVARCHAR(255),full_nameVARCHAR(255),usernameVARCHAR(255),emailVARCHAR(255),phoneVARCHAR(255),last_loginDATETIME,auth_client_idsVARCHAR(255),genderVARCHAR(255),dobDATETIME,designationVARCHAR(255),timezoneVARCHAR(255),statusVARCHAR(255),localeVARCHAR(255),user_tenant_idVARCHAR(255),role_idVARCHAR(255),tenant_idVARCHAR(255),role_typeINTEGER,nameVARCHAR(255),user_lockedTINYINT(1),npiVARCHAR(255),photo_urlVARCHAR(255),practicing_sinceDATETIME,departmentVARCHAR(255),specialityVARCHAR(255),schedulingTINYINT(1),adhocTINYINT(1),presenceINTEGER,patientPresenterOrgsINTEGER[],is_master_tenantTINYINT(1),tenant_nameVARCHAR(255),statesVARCHAR(255)[],license_idVARCHAR(255),user_configsJSON);", }, original: { errno: 1, code: "SQLITE_ERROR", sql: "CREATE TABLE IF NOT EXISTSv_users (deletedTINYINT(1) DEFAULT 0,deleted_onDATETIME,deleted_byVARCHAR(255),created_onDATETIME,modified_onDATETIME,created_byVARCHAR(255),modified_byVARCHAR(255),suffixVARCHAR(255),first_nameVARCHAR(255),last_nameVARCHAR(255),full_nameVARCHAR(255),usernameVARCHAR(255),emailVARCHAR(255),phoneVARCHAR(255),last_loginDATETIME,auth_client_idsVARCHAR(255),genderVARCHAR(255),dobDATETIME,designationVARCHAR(255),timezoneVARCHAR(255),statusVARCHAR(255),localeVARCHAR(255),user_tenant_idVARCHAR(255),role_idVARCHAR(255),tenant_idVARCHAR(255),role_typeINTEGER,nameVARCHAR(255),user_lockedTINYINT(1),npiVARCHAR(255),photo_urlVARCHAR(255),practicing_sinceDATETIME,departmentVARCHAR(255),specialityVARCHAR(255),schedulingTINYINT(1),adhocTINYINT(1),presenceINTEGER,patientPresenterOrgsINTEGER[],is_master_tenantTINYINT(1),tenant_nameVARCHAR(255),statesVARCHAR(255)[],license_idVARCHAR(255),user_configsJSON);", }, sql: "CREATE TABLE IF NOT EXISTSv_users (deletedTINYINT(1) DEFAULT 0,deleted_onDATETIME,deleted_byVARCHAR(255),created_onDATETIME,modified_onDATETIME,created_byVARCHAR(255),modified_byVARCHAR(255),suffixVARCHAR(255),first_nameVARCHAR(255),last_nameVARCHAR(255),full_nameVARCHAR(255),usernameVARCHAR(255),emailVARCHAR(255),phoneVARCHAR(255),last_loginDATETIME,auth_client_idsVARCHAR(255),genderVARCHAR(255),dobDATETIME,designationVARCHAR(255),timezoneVARCHAR(255),statusVARCHAR(255),localeVARCHAR(255),user_tenant_idVARCHAR(255),role_idVARCHAR(255),tenant_idVARCHAR(255),role_typeINTEGER,nameVARCHAR(255),user_lockedTINYINT(1),npiVARCHAR(255),photo_urlVARCHAR(255),practicing_sinceDATETIME,departmentVARCHAR(255),specialityVARCHAR(255),schedulingTINYINT(1),adhocTINYINT(1),presenceINTEGER,patientPresenterOrgsINTEGER[],is_master_tenantTINYINT(1),tenant_nameVARCHAR(255),statesVARCHAR(255)[],license_idVARCHAR(255),user_configs JSON);", parameters: { }, }

This is my complete model file :

import {model, property} from '@loopback/repository';
import {UserModifiableEntity, UserStatus} from '@sourceloop/core';
import {
AuditLogGroups,
CommonErrors,
Gender,
PatientPresenterOrg,
PATTERNS,
Presence,
RoleType,
STATES,
Title,
} from '..';
import {Locales} from '../enums';
import {Config} from '../interfaces/user-config.interface';

@model({
name: 'v_users',
description: 'The model definition for user.',
settings: {
logGroup: AuditLogGroups.UserLogs,
allowExtendedOperators: true,
},
})
export class UserView extends UserModifiableEntity {
@property({
type: 'string',
id: true,
generated: true,
description: 'The unique identifier for the user.',
})
id?: string;

@property({
type: 'string',
jsonSchema: {
enum: [Title.Dr, Title.Mr, Title.Mrs, Title.Ms],
},
required: false,
description: 'The title or prefix for the user (e.g., Mr, Mrs, Dr).',
})
suffix?: Title;

@property({
type: 'string',
jsonSchema: {
pattern: PATTERNS.alphabetsOnlyPattern,
errorMessage: CommonErrors.ALLOWED_MIDDLENAME,
},
required: true,
name: 'first_name',
description: 'The first name of the user.',
})
firstName: string;

@property({
type: 'string',
jsonSchema: {
pattern: PATTERNS.alphabetsOnlyPattern,
errorMessage: CommonErrors.ALLOWED_LASTNAME,
},
name: 'last_name',
description: 'The last name of the user.',
})
lastName: string;

@property({
type: 'string',
name: 'full_name',
description:
'The full name of the user (combination of first and last name).',
})
fullName: string;

@property({
type: 'string',
required: false,
description: 'The username of the user.',
})
username: string;

@property({
type: 'string',
jsonSchema: {
pattern: PATTERNS.emailPatter,
errorMessage: CommonErrors.ALLOWED_EMAIL,
},
required: true,
description: 'The email address of the user.',
})
email: string;

@property({
type: 'string',
jsonSchema: {
pattern: PATTERNS.phonePattern,
errorMessage: CommonErrors.ALLOWED_PHONE,
},
name: 'phone',
description: 'The phone number of the user.',
})
'phone'?: string;

@property({
type: 'date',
name: 'last_login',
postgresql: {
column: 'last_login',
},
description: "The timestamp of the user's last login.",
})
lastLogin?: Date;

@property({
type: 'string',
name: 'auth_client_ids',
description: "The client IDs associated with the user's authentication.",
})
authClientIds: string;

@property({
type: 'string',
description:
'The gender of the user (M for male, F for female, O for other).',
})
gender?: Gender;

@property({
type: 'date',
description: 'The date of birth of the user.',
})
dob: Date;

@property({
type: 'string',
name: 'designation',
description: 'The designation or job title of the user.',
})
designation?: string;

@property({
type: 'string',
name: 'timezone',
description: 'The timezone of the user.',
})
timezone?: string;

@property({
type: 'string',
name: 'status',
description: 'The status of the user (e.g., Active, Inactive).',
})
status: UserStatus;

@property({
type: 'string',
name: 'locale',
description: 'The locale or language preference of the user.',
})
locale: Locales;

@property({
type: 'string',
name: 'user_tenant_id',
description: "The ID of the user's tenant.",
})
userTenantId: string;

@property({
type: 'string',
name: 'role_id',
description: "The ID of the user's role.",
})
roleId: string;

@property({
type: 'string',
name: 'tenant_id',
description: 'The ID of the tenant associated with the user.',
})
tenantId: string;

@property({
type: 'number',
name: 'role_type',
description: "The type of the user's role.",
})
roleType: RoleType;

@property({
type: 'string',
name: 'name',
description: "The name associated with the user's role.",
})
roleName: string;

@property({
type: 'boolean',
name: 'user_locked',
description: 'Indicates whether the user is locked or not.',
})
userLocked: boolean;

@property({
type: 'string',
description: 'The NPI (National Provider Identifier) of the user.',
})
npi?: string;

@property({
name: 'photo_url',
type: 'string',
description: "The URL of the user's profile photo.",
})
imageKey?: string;

@property({
name: 'photo_url',
type: 'string',
description: "The URL of the user's profile photo.",
})
photoUrl?: string;

@property({
type: 'date',
name: 'practicing_since',
description: 'The date since which the user has been practicing.',
})
praticingSince?: string;

@property({
type: 'string',
description: 'The department or specialty of the user.',
})
department?: string;

@property({
type: 'string',
description: 'The specialty of the user.',
})
speciality?: string;

@property({
type: 'boolean',
description: 'Indicates if the user has scheduling privileges.',
})
scheduling?: boolean;

@property({
type: 'boolean',
description: 'Indicates if the user has adhoc privileges.',
})
adhoc?: boolean;

@property({
type: 'number',
description: 'The presence status of the user.',
})
presence: Presence;

@property({
type: 'array',
itemType: 'object',
name: 'patientPresenterOrgs',
description:
'Organizations associated with the user as patient presenters.',
})
patientPresenterOrgs?: PatientPresenterOrg[];

@property({
type: 'boolean',
name: 'is_master_tenant',
description: 'Indicates if the user is a master tenant.',
})
isMasterTenant?: boolean;

@property({
type: 'string',
name: 'tenant_name',
description: 'The name of the tenant associated with the user.',
})
tenantName?: string;

@property({
type: 'array',
name: 'states',
itemType: 'string',
jsonSchema: {
enum: STATES.STATE,
errorMessage: CommonErrors.ALLOWED_STATE,
},
description: 'The states associated with the user.',
})
states?: string[];

@property({
type: 'string',
name: 'license_id',
description: 'The license ID of the user.',
})
licenceId: string;

@property({
type: 'object',
name: 'user_configs',
description: 'config for individual user',
})
userConfigs?: Config;

constructor(data?: Partial) {
super(data);
}
}

export type UserViewWithRelations = UserView;

Logs

No response

Additional information

No response

Reproduction

Given all required details in description

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

@loopback/sequelize の syncSequelizeModel から始め、特に 861 行目付近の sequelize.repository.base.ts を確認し、pull request 10284 で導入された動作と比較してください。UserView の patientPresenterOrgs プロパティと SQLite を使って問題を再現してください。同期によって無効な INTEGER[] または VARCHAR(255)[] のカラム定義が生成されなくなれば完了です。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
node.js, sqlite, typescript
領域
backend, databases
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
停滞
明瞭さ
おおむね明確
初心者へのやさしさ
25/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。