RQQuestionDBManager.m 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  1. //
  2. // RQQuestionDBManager.m
  3. // SDJK
  4. //
  5. // Created by 张嵘 on 2021/8/20.
  6. //
  7. #import "RQQuestionDBManager.h"
  8. static NSString *dbNameStr = @"question";
  9. static NSString *dbTypeStr = @"db";
  10. static NSString *questionTableNameStr = @"question_info";
  11. @interface RQQuestionDBManager ()
  12. @property (nonatomic, readwrite, strong) FMDatabaseQueue *databaseQueue;
  13. @end
  14. @implementation RQQuestionDBManager
  15. static id rq_questionDBManager = nil;
  16. #pragma mark - init
  17. + (instancetype)sharedInstance {
  18. static dispatch_once_t onceToken;
  19. dispatch_once(&onceToken, ^{
  20. rq_questionDBManager = [[self alloc] init];
  21. });
  22. return rq_questionDBManager;
  23. }
  24. - (instancetype)init {
  25. if (self = [super init]) {
  26. NSString *resourcePath = [[NSBundle mainBundle] pathForResource:@"question" ofType:@"db"];
  27. [self initDatabaseQueueWithResourcePath:resourcePath];
  28. }
  29. return self;
  30. }
  31. - (void)initDatabaseQueueWithResourcePath:(NSString *)resourcePath {
  32. NSError *error;
  33. NSString *dbPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:[NSString stringWithFormat:@"question.db"]];
  34. if ([RQFileManager isPathExist:dbPath]) {
  35. self.databaseQueue = [FMDatabaseQueue databaseQueueWithPath:dbPath];
  36. NSLog(@"数据库path-----%@",dbPath);
  37. if ([self getQuestionVersion] >= [self getQuestionVersionWithResourcePath:resourcePath]) {
  38. } else {
  39. [[RQFileManager fileManager] removeItemAtPath:dbPath error:&error];
  40. [[RQFileManager fileManager] copyItemAtPath:resourcePath toPath:[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:[NSString stringWithFormat:@"question.db"]] error:&error];
  41. self.databaseQueue = [FMDatabaseQueue databaseQueueWithPath:dbPath];
  42. }
  43. } else {
  44. [[RQFileManager fileManager] copyItemAtPath:resourcePath toPath:[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:[NSString stringWithFormat:@"question.db"]] error:&error];
  45. self.databaseQueue = [FMDatabaseQueue databaseQueueWithPath:dbPath];
  46. NSLog(@"数据库path-----%@",dbPath);
  47. }
  48. }
  49. #pragma mark - Public Method
  50. - (NSArray *)getColumnWithCarType:(RQHomePageCarType)carType subject:(RQHomePageSubjectType)subject pageType:(RQHomeSubPageType)pageType {
  51. /// 默认为轿车 cart,bus,truck
  52. NSString *queryCarTypeStr = @"model LIKE '%cart%'";
  53. switch (carType) {
  54. case RQHomePageCarType_Car:
  55. queryCarTypeStr = @"model LIKE '%cart%'";
  56. break;
  57. case RQHomePageCarType_Bus:
  58. queryCarTypeStr = @"model LIKE '%bus%'";
  59. break;
  60. case RQHomePageCarType_Truck:
  61. queryCarTypeStr = @"model LIKE '%truck%'";
  62. break;
  63. case RQHomePageCarType_Motorcycle:
  64. queryCarTypeStr = @"model LIKE '%mtc%'";
  65. break;
  66. default:
  67. break;
  68. }
  69. /// 默认科目一
  70. NSString *querySubjectTypeStr = @"k1";
  71. switch (subject) {
  72. case RQHomePageSubjectType_SubjectOne:
  73. querySubjectTypeStr = @"k1";
  74. break;
  75. case RQHomePageSubjectType_SubjectTwo:
  76. querySubjectTypeStr = @"k2";
  77. break;
  78. case RQHomePageSubjectType_SubjectThree:
  79. querySubjectTypeStr = @"k3";
  80. break;
  81. case RQHomePageSubjectType_SubjectFour:
  82. querySubjectTypeStr = @"k4";
  83. break;
  84. default:
  85. break;
  86. }
  87. /// 默认顺序练习
  88. NSString *pageTypeStr = @"title";
  89. NSString *pageTypeByOrderStr = @"sort";
  90. switch (pageType) {
  91. case RQHomeSubPageType_SequentialPractice:/// 顺序练习
  92. pageTypeStr = @"title,column_id";
  93. pageTypeByOrderStr = @"sort";
  94. querySubjectTypeStr = [NSString stringWithFormat:@"subject = '%@'",querySubjectTypeStr];
  95. break;
  96. case RQHomeSubPageType_LocalTopics: /// 地方专题
  97. pageTypeStr = @"place_issue_name";
  98. pageTypeByOrderStr = @"place_issue";
  99. break;
  100. case RQHomeSubPageType_ClassificationExercise:/// 分类练习
  101. pageTypeStr = @"title,column_id";
  102. pageTypeByOrderStr = @"sort";
  103. querySubjectTypeStr = [NSString stringWithFormat:@"%@_3",querySubjectTypeStr];
  104. querySubjectTypeStr = [NSString stringWithFormat:@"subject = '%@'",querySubjectTypeStr];
  105. break;
  106. case RQHomeSubPageType_SelectedTestQuestions: //精选考题
  107. pageTypeStr = @"title,column_id";
  108. pageTypeByOrderStr = @"sort";
  109. querySubjectTypeStr = [NSString stringWithFormat:@"%@_2",querySubjectTypeStr];
  110. querySubjectTypeStr = [NSString stringWithFormat:@"subject = '%@'",querySubjectTypeStr];
  111. break;
  112. default:
  113. break;
  114. }
  115. //v1.1.2 旧逻辑
  116. // NSString *queryStr = [NSString stringWithFormat:@"select distinct %@ from question_info where %@ and %@ %@ order by %@ + 0 ASC", pageTypeStr, queryCarTypeStr, querySubjectTypeStr, (pageType == RQHomeSubPageType_LocalTopics)? @"and place_issue IS NOT NULL" : @"", pageTypeByOrderStr];
  117. //v1.1.3
  118. NSString *queryStr = [NSString stringWithFormat:@"select distinct %@ from question_column where %@ and %@ order by %@ + 0 ASC", pageTypeStr, queryCarTypeStr, querySubjectTypeStr, pageTypeByOrderStr];
  119. // select distinct * from WHERE subject = 'k1_2' AND model LIKE '%cart%' order by sort ASC
  120. NSMutableArray *arr = @[].mutableCopy;
  121. @weakify(arr)
  122. [_databaseQueue inTransaction:^(FMDatabase * _Nonnull db, BOOL * _Nonnull rollback) {
  123. @try {
  124. @strongify(arr)
  125. FMResultSet *resultSet = [db executeQuery:queryStr];
  126. while ([resultSet next]) {
  127. if([pageTypeStr containsString:@","]){
  128. NSString *str = [resultSet stringForColumn:@"title"];
  129. NSString *strCol = [resultSet stringForColumn:@"column_id"];
  130. NSString *str_title = [NSString stringWithFormat:@"%@,%@",str,strCol];
  131. // 对应字段来取数据
  132. [arr addObject:str_title? : @"地方题"];
  133. }else{
  134. NSString *str = [resultSet stringForColumn:pageTypeStr];
  135. // 对应字段来取数据
  136. [arr addObject:str? : @"地方题"];
  137. }
  138. }
  139. if ([arr containsObject:@"地方题"] && [arr indexOfObject:@"地方题"] == 0) {
  140. NSString *saveStr = arr.firstObject;
  141. [arr removeFirstObject];
  142. [arr addObject:saveStr];
  143. }
  144. } @catch (NSException *exception) {
  145. *rollback = YES;
  146. } @finally {
  147. *rollback = NO;
  148. }
  149. }];
  150. return arr.copy;
  151. }
  152. - (NSArray *)getQuestionWithCarType:(RQHomePageCarType)carType subject:(RQHomePageSubjectType)subject pageType:(RQHomeSubPageType)pageType name:(NSString *)name exerciseType:(RQExerciseType)exerciseType {
  153. NSMutableArray *arr = @[].mutableCopy;
  154. /// 默认为轿车 cart,bus,truck
  155. NSString *queryCarTypeStr = @"model LIKE '%cart%'";
  156. switch (carType) {
  157. case RQHomePageCarType_Car:
  158. queryCarTypeStr = @"model LIKE '%cart%'";
  159. break;
  160. case RQHomePageCarType_Bus:
  161. queryCarTypeStr = @"model LIKE '%bus%'";
  162. break;
  163. case RQHomePageCarType_Truck:
  164. queryCarTypeStr = @"model LIKE '%truck%'";
  165. break;
  166. case RQHomePageCarType_Motorcycle:
  167. queryCarTypeStr = @"model LIKE '%mtc%'";
  168. break;
  169. default:
  170. break;
  171. }
  172. /// 默认科目一
  173. NSString *querySubjectTypeStr = @"subject = 1";
  174. switch (subject) {
  175. case RQHomePageSubjectType_SubjectOne:
  176. querySubjectTypeStr = @"subject = 1";
  177. break;
  178. case RQHomePageSubjectType_SubjectTwo:
  179. querySubjectTypeStr = @"subject = 2";
  180. break;
  181. case RQHomePageSubjectType_SubjectThree:
  182. querySubjectTypeStr = @"subject = 3";
  183. break;
  184. case RQHomePageSubjectType_SubjectFour:
  185. querySubjectTypeStr = @"subject = 4";
  186. break;
  187. default:
  188. break;
  189. }
  190. /// 默认顺序练习
  191. // NSString *pageTypeStr = @"seque_issue_name";
  192. // NSString *pageTypeByOrderStr = @"seque_issue";
  193. NSString *nameStr = @"";
  194. NSString *orderStr = @"";
  195. NSString *colidStr = @"";
  196. if([name containsString:@","]){
  197. colidStr = [[name componentsSeparatedByString:@","] lastObject];
  198. }
  199. switch (pageType) {
  200. //// pageTypeStr = @"place_issue_name";
  201. //// pageTypeByOrderStr = @"place_issue";
  202. // nameStr = [NSString stringWithFormat:@"and place_issue_name = '%@'",name];
  203. // orderStr = @"number";
  204. // break;
  205. case RQHomeSubPageType_LocalTopics:
  206. case RQHomeSubPageType_ClassificationExercise:
  207. case RQHomeSubPageType_SequentialPractice:
  208. case RQHomeSubPageType_SelectedTestQuestions:
  209. // pageTypeStr = @"excell_issue_name";
  210. // pageTypeByOrderStr = @"excell_issue";
  211. nameStr = [NSString stringWithFormat:@"(INSTR ( column_all, ',' || '%@' || ',' ) > 0 OR INSTR ( column_all, '%@' || ',' ) = 1 OR INSTR ( column_all, ',' || '%@' ) = ( length( column_all ) - length( ',' || '%@' ) ) + 1 OR column_all = '%@')",colidStr,colidStr,colidStr,colidStr,colidStr];
  212. orderStr = @"number";
  213. break;
  214. default:
  215. break;
  216. }
  217. if (RQStringIsEmpty(name)) {
  218. nameStr = @"";
  219. }
  220. /// excell_sort
  221. /// 默认按_id排序
  222. NSString *exerciseTypeStr = [NSString stringWithFormat:@"%@ + 0 ASC", orderStr];
  223. switch (exerciseType) {
  224. case RQExerciseType_Sequential:
  225. // exerciseTypeStr = [NSString stringWithFormat:@"%@ + 0 ASC", orderStr];
  226. break;
  227. case RQExerciseType_Random:
  228. exerciseTypeStr = @"random()";
  229. break;
  230. case RQExerciseType_Recitation:
  231. // exerciseTypeStr = [NSString stringWithFormat:@"%@ + 0 ASC", orderStr];
  232. break;
  233. case RQExerciseType_Test:
  234. exerciseTypeStr = @"random() limit 50";
  235. break;
  236. case RQExerciseType_Exam:
  237. exerciseTypeStr = @"random() limit 5";
  238. break;
  239. default:
  240. break;
  241. }
  242. // resultSet = [_db executeQuery:@"select * from question_info where answer like '%-%'"];
  243. NSString *queryStr = [NSString stringWithFormat:@"select * from question_info where %@ and %@ order by %@", queryCarTypeStr, nameStr, exerciseTypeStr];
  244. @weakify(queryStr)
  245. if (pageType == RQHomeSubPageType_MockExamination && exerciseType == RQExerciseType_Test) {
  246. NSString *excellIssueNameStr = (carType == RQHomePageCarType_Motorcycle)? @"" : @"AND excell_issue_name LIKE '%%必%%'";
  247. NSString *newExcellIssueNameStr = (carType == RQHomePageCarType_Motorcycle)? @"" : @"AND excell_issue_name LIKE '%%新%%'";
  248. RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
  249. @strongify(queryStr)
  250. queryStr = [NSString stringWithFormat:@"select * from question_info where %@ and %@ %@ and question_type = 1 and place_issue IS NULL %@ order by %@", queryCarTypeStr, querySubjectTypeStr, nameStr, excellIssueNameStr, [self getQuestionNumQueryStrWithCarType:carType subject:subject questionType:RQQuestionType_Judgment isNew:NO]];
  251. [subscriber sendNext:[self queryQuestionWithQueryStr:queryStr exerciseType:exerciseType]];
  252. [subscriber sendCompleted];
  253. return [RACDisposable disposableWithBlock:^{
  254. }];
  255. }];
  256. RACSignal *signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
  257. @strongify(queryStr)
  258. queryStr = [NSString stringWithFormat:@"select * from question_info where %@ and %@ %@ and question_type = 1 and place_issue IS NULL %@ order by %@", queryCarTypeStr, querySubjectTypeStr, nameStr, newExcellIssueNameStr, [self getQuestionNumQueryStrWithCarType:carType subject:subject questionType:RQQuestionType_Judgment isNew:YES]];
  259. [subscriber sendNext:[self queryQuestionWithQueryStr:queryStr exerciseType:exerciseType]];
  260. [subscriber sendCompleted];
  261. return [RACDisposable disposableWithBlock:^{
  262. }];
  263. }];
  264. RACSignal *signal3 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
  265. @strongify(queryStr)
  266. queryStr = [NSString stringWithFormat:@"select * from question_info where %@ and %@ %@ and question_type = 2 and place_issue IS NULL %@ order by %@", queryCarTypeStr, querySubjectTypeStr, nameStr, excellIssueNameStr, [self getQuestionNumQueryStrWithCarType:carType subject:subject questionType:RQQuestionType_SingleChoice isNew:NO]];
  267. [subscriber sendNext:[self queryQuestionWithQueryStr:queryStr exerciseType:exerciseType]];
  268. [subscriber sendCompleted];
  269. return [RACDisposable disposableWithBlock:^{
  270. }];
  271. }];
  272. RACSignal *signal4 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
  273. @strongify(queryStr)
  274. queryStr = [NSString stringWithFormat:@"select * from question_info where %@ and %@ %@ and question_type = 2 and place_issue IS NULL %@ order by %@", queryCarTypeStr, querySubjectTypeStr, nameStr, newExcellIssueNameStr, [self getQuestionNumQueryStrWithCarType:carType subject:subject questionType:RQQuestionType_SingleChoice isNew:YES]];
  275. [subscriber sendNext:[self queryQuestionWithQueryStr:queryStr exerciseType:exerciseType]];
  276. [subscriber sendCompleted];
  277. return [RACDisposable disposableWithBlock:^{
  278. }];
  279. }];
  280. RACSignal *signal5 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
  281. @strongify(queryStr)
  282. queryStr = [NSString stringWithFormat:@"select * from question_info where %@ and %@ %@ and question_type = 3 and place_issue IS NULL %@ order by %@", queryCarTypeStr, querySubjectTypeStr, nameStr, excellIssueNameStr, [self getQuestionNumQueryStrWithCarType:carType subject:subject questionType:RQQuestionType_MultipleChoice isNew:NO]];
  283. [subscriber sendNext:[self queryQuestionWithQueryStr:queryStr exerciseType:exerciseType]];
  284. [subscriber sendCompleted];
  285. return [RACDisposable disposableWithBlock:^{
  286. }];
  287. }];
  288. RACSignal *signal6 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
  289. @strongify(queryStr)
  290. queryStr = [NSString stringWithFormat:@"select * from question_info where %@ and %@ %@ and question_type = 3 and place_issue IS NULL %@ order by %@", queryCarTypeStr, querySubjectTypeStr, nameStr, newExcellIssueNameStr, [self getQuestionNumQueryStrWithCarType:carType subject:subject questionType:RQQuestionType_MultipleChoice isNew:YES]];
  291. [subscriber sendNext:[self queryQuestionWithQueryStr:queryStr exerciseType:exerciseType]];
  292. [subscriber sendCompleted];
  293. return [RACDisposable disposableWithBlock:^{
  294. }];
  295. }];
  296. RACSignal *signal = [RACSignal combineLatest:@[signal1, signal2, signal3, signal4, signal5, signal6] reduce:^id (NSArray *arr1, NSArray *arr2, NSArray *arr3, NSArray *arr4, NSArray *arr5, NSArray *arr6) {
  297. NSMutableArray *judgmentArr = @[].mutableCopy;
  298. [judgmentArr addObjectsFromArray:arr1];
  299. [judgmentArr addObjectsFromArray:arr2];
  300. judgmentArr = [judgmentArr rq_randomArray].mutableCopy;
  301. NSMutableArray *singleChoiceArr = @[].mutableCopy;
  302. [singleChoiceArr addObjectsFromArray:arr3];
  303. [singleChoiceArr addObjectsFromArray:arr4];
  304. singleChoiceArr = [singleChoiceArr rq_randomArray].mutableCopy;
  305. NSMutableArray *multipleChoiceArr = @[].mutableCopy;
  306. [multipleChoiceArr addObjectsFromArray:arr5];
  307. [multipleChoiceArr addObjectsFromArray:arr6];
  308. multipleChoiceArr = [multipleChoiceArr rq_randomArray].mutableCopy;
  309. [arr addObjectsFromArray:judgmentArr];
  310. [arr addObjectsFromArray:singleChoiceArr];
  311. [arr addObjectsFromArray:multipleChoiceArr];
  312. return arr.copy;
  313. }];
  314. [signal subscribeNext:^(NSArray *allArr) {
  315. }];
  316. return arr.copy;
  317. } else if (pageType == RQHomeSubPageType_MockExamination && exerciseType == RQExerciseType_Exam) {
  318. @weakify(self)
  319. RACSignal *signal0 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
  320. NSMutableArray *difficultArr = @[].mutableCopy;
  321. [[[self getExamRuleWithCarType:carType subject:subject].rac_sequence.signal map:^id _Nullable(RQExamRuleModel *examRuleModel) {
  322. NSString *chapterIdStr = [NSString stringWithFormat:@"chapter_id = %ld",(long)examRuleModel.chapter_id];
  323. NSString *typeStr = [NSString stringWithFormat:@"question_type IN %@",(subject == RQHomePageSubjectType_SubjectOne)? @"(1, 2)" : @"(1, 2, 3)"];
  324. NSString *randomStr = [NSString stringWithFormat:@"RANDOM() LIMIT %@",[NSString qmui_stringWithNSInteger:examRuleModel.difficult_count]];
  325. NSString *difficultQueryStr = [NSString stringWithFormat:@"SELECT * FROM %@ WHERE %@ AND %@ AND diff_degree IN (4, 5) AND place_issue IS NULL AND %@ AND %@ ORDER BY %@",questionTableNameStr , queryCarTypeStr, querySubjectTypeStr, chapterIdStr, typeStr, randomStr];
  326. return difficultQueryStr;
  327. }].toArray.rac_sequence.signal subscribeNext:^(NSString *difficultQueryStr) {
  328. @strongify(self)
  329. [difficultArr addObjectsFromArray:[self queryQuestionWithQueryStr:difficultQueryStr]];
  330. } completed:^{
  331. [subscriber sendNext:difficultArr.copy];
  332. [subscriber sendCompleted];
  333. }];
  334. return [RACDisposable disposableWithBlock:^{}];
  335. }];
  336. RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
  337. NSMutableArray *judgeArr = @[].mutableCopy;
  338. [[[self getExamRuleWithCarType:carType subject:subject].rac_sequence.signal map:^id _Nullable(RQExamRuleModel *examRuleModel) {
  339. NSString *chapterIdStr = [NSString stringWithFormat:@"AND chapter_id = %ld",(long)examRuleModel.chapter_id];
  340. NSString *judgeCountStr = [NSString stringWithFormat:@"RANDOM() LIMIT %ld",(long)examRuleModel.judge_count];
  341. NSString *judgeQueryStr = [NSString stringWithFormat:@"SELECT * FROM %@ WHERE %@ AND %@ AND question_type = 1 AND diff_degree IN (0,1,2,3) AND place_issue IS NULL %@ ORDER BY %@",questionTableNameStr , queryCarTypeStr, querySubjectTypeStr, chapterIdStr, judgeCountStr];
  342. NSMutableArray *judgeChapterArr = [self queryQuestionWithQueryStr:judgeQueryStr].mutableCopy;
  343. if (judgeChapterArr.count < examRuleModel.judge_count) {
  344. NSString *judgeQueryAddStr = [NSString stringWithFormat:@"SELECT DISTINCT * FROM %@ WHERE %@ AND %@ AND question_type = 1 AND diff_degree IN (4,5) AND place_issue IS NULL %@ ORDER BY RANDOM() LIMIT %@",questionTableNameStr , queryCarTypeStr, querySubjectTypeStr, chapterIdStr, [NSString stringWithFormat:@"%ld",(long)(examRuleModel.judge_count - judgeChapterArr.count)]];
  345. NSArray *judgeChapterAddArr = [self queryQuestionWithQueryStr:judgeQueryAddStr];
  346. [judgeChapterArr addObjectsFromArray:judgeChapterAddArr];
  347. return judgeChapterArr.copy;
  348. } else {
  349. return judgeChapterArr.copy;
  350. }
  351. }].toArray.rac_sequence.signal subscribeNext:^(NSArray *judgeChapterArr) {
  352. [judgeArr addObjectsFromArray:judgeChapterArr];
  353. } completed:^{
  354. [subscriber sendNext:judgeArr.copy];
  355. [subscriber sendCompleted];
  356. }];
  357. return [RACDisposable disposableWithBlock:^{}];
  358. }];
  359. RACSignal *signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
  360. NSMutableArray *choiceArr = @[].mutableCopy;
  361. [[[self getExamRuleWithCarType:carType subject:subject].rac_sequence.signal map:^id _Nullable(RQExamRuleModel *examRuleModel) {
  362. NSString *chapterIdStr = [NSString stringWithFormat:@"AND chapter_id = %ld",(long)examRuleModel.chapter_id];
  363. NSString *choiceCountStr = [NSString stringWithFormat:@"RANDOM() LIMIT %ld",(long)examRuleModel.choice_count];
  364. NSString *choiceQueryStr = [NSString stringWithFormat:@"SELECT * FROM %@ WHERE %@ AND %@ AND question_type = 2 AND diff_degree IN (0,1,2,3) AND place_issue IS NULL %@ ORDER BY %@",questionTableNameStr , queryCarTypeStr, querySubjectTypeStr, chapterIdStr, choiceCountStr];
  365. NSMutableArray *choiceChapterArr = [self queryQuestionWithQueryStr:choiceQueryStr].mutableCopy;
  366. if (choiceChapterArr.count < examRuleModel.choice_count) {
  367. NSString *choiceQueryAddStr = [NSString stringWithFormat:@"SELECT DISTINCT * FROM %@ WHERE %@ AND %@ AND question_type = 2 AND diff_degree IN (4,5) AND place_issue IS NULL %@ ORDER BY RANDOM() LIMIT %@",questionTableNameStr , queryCarTypeStr, querySubjectTypeStr, chapterIdStr, [NSString stringWithFormat:@"%ld",(long)(examRuleModel.choice_count - choiceChapterArr.count)]];
  368. NSArray *choiceChapterAddArr = [self queryQuestionWithQueryStr:choiceQueryAddStr];
  369. [choiceChapterArr addObjectsFromArray:choiceChapterAddArr];
  370. return choiceChapterArr.copy;
  371. } else {
  372. return choiceChapterArr.copy;
  373. }
  374. }].toArray.rac_sequence.signal subscribeNext:^(NSArray *choiceChapterArr) {
  375. [choiceArr addObjectsFromArray:choiceChapterArr];
  376. } completed:^{
  377. [subscriber sendNext:choiceArr.copy];
  378. [subscriber sendCompleted];
  379. }];
  380. return [RACDisposable disposableWithBlock:^{}];
  381. }];
  382. RACSignal *signal3 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
  383. NSMutableArray *multipleChoiceArr = @[].mutableCopy;
  384. [[[self getExamRuleWithCarType:carType subject:subject].rac_sequence.signal map:^id _Nullable(RQExamRuleModel *examRuleModel) {
  385. NSString *chapterIdStr = [NSString stringWithFormat:@"AND chapter_id = %ld",(long)examRuleModel.chapter_id];
  386. NSString *multipleChoiceCountStr = [NSString stringWithFormat:@"RANDOM() LIMIT %ld",(long)examRuleModel.multiple_choice_count];
  387. NSString *multipleChoiceQueryStr = [NSString stringWithFormat:@"SELECT * FROM %@ WHERE %@ AND %@ AND question_type = 3 AND diff_degree IN (0,1,2,3) AND place_issue IS NULL %@ ORDER BY %@",questionTableNameStr , queryCarTypeStr, querySubjectTypeStr, chapterIdStr, multipleChoiceCountStr];
  388. NSMutableArray *multipleChoiceChapterArr = [self queryQuestionWithQueryStr:multipleChoiceQueryStr].mutableCopy;
  389. if (multipleChoiceChapterArr.count < examRuleModel.multiple_choice_count) {
  390. NSString *multipleChoiceQueryAddStr = [NSString stringWithFormat:@"SELECT DISTINCT * FROM %@ WHERE %@ AND %@ AND question_type = 3 AND diff_degree IN (4,5) AND place_issue IS NULL %@ ORDER BY RANDOM() LIMIT %@",questionTableNameStr , queryCarTypeStr, querySubjectTypeStr, chapterIdStr, [NSString stringWithFormat:@"%ld",(long)(examRuleModel.multiple_choice_count - multipleChoiceChapterArr.count)]];
  391. NSArray *multipleChoiceChapterAddArr = [self queryQuestionWithQueryStr:multipleChoiceQueryAddStr];
  392. [multipleChoiceChapterArr addObjectsFromArray:multipleChoiceChapterAddArr];
  393. return multipleChoiceChapterArr.copy;
  394. } else {
  395. return multipleChoiceChapterArr.copy;
  396. }
  397. }].toArray.rac_sequence.signal subscribeNext:^(NSArray *multipleChoiceChapterArr) {
  398. [multipleChoiceArr addObjectsFromArray:multipleChoiceChapterArr];
  399. } completed:^{
  400. [subscriber sendNext:multipleChoiceArr.copy];
  401. [subscriber sendCompleted];
  402. }];
  403. return [RACDisposable disposableWithBlock:^{}];
  404. }];
  405. return [[[RACSignal combineLatest:@[signal0, signal1, signal2, signal3] reduce:^id (NSArray *arr0, NSArray *arr1, NSArray *arr2, NSArray *arr3){
  406. NSMutableArray *judgeArr = [NSMutableArray arrayWithArray:arr1];
  407. NSMutableArray *choiceArr = [NSMutableArray arrayWithArray:arr2];
  408. NSMutableArray *multipleChoiceArr = [NSMutableArray arrayWithArray:arr3];
  409. dispatch_semaphore_t sema = dispatch_semaphore_create(0);
  410. [[arr0.rac_sequence.signal filter:^BOOL(RQExerciseModel *difficultQuestionModel) {
  411. return ![judgeArr containsObject:difficultQuestionModel] && ![choiceArr containsObject:difficultQuestionModel] && ![multipleChoiceArr containsObject:difficultQuestionModel];
  412. }].toArray.rac_sequence.signal subscribeNext:^(RQExerciseModel *difficultQuestionModel) {
  413. if (difficultQuestionModel.question_type == 1) {
  414. NSMutableArray *sortChapterArr = [judgeArr.rac_sequence.signal filter:^BOOL(RQExerciseModel *judgeQuestionModel) {
  415. return (judgeQuestionModel.chapter_id == difficultQuestionModel.chapter_id) && ![arr0 containsObject:judgeQuestionModel];
  416. }].toArray.mutableCopy;
  417. if (sortChapterArr.count > 0) {
  418. [judgeArr replaceObjectAtIndex:[judgeArr indexOfObject:sortChapterArr.lastObject] withObject:difficultQuestionModel];
  419. }
  420. } else if (difficultQuestionModel.question_type == 2) {
  421. NSMutableArray *sortChapterArr = [choiceArr.rac_sequence.signal filter:^BOOL(RQExerciseModel *choiceQuestionModel) {
  422. return (choiceQuestionModel.chapter_id == difficultQuestionModel.chapter_id) && ![arr0 containsObject:choiceQuestionModel];
  423. }].toArray.mutableCopy;
  424. if (sortChapterArr.count > 0) {
  425. [choiceArr replaceObjectAtIndex:[choiceArr indexOfObject:sortChapterArr.lastObject] withObject:difficultQuestionModel];
  426. }
  427. } else {
  428. NSMutableArray *sortChapterArr = [multipleChoiceArr.rac_sequence.signal filter:^BOOL(RQExerciseModel *multiChoiceQuestionModel) {
  429. return (multiChoiceQuestionModel.chapter_id == difficultQuestionModel.chapter_id) && ![arr0 containsObject:multiChoiceQuestionModel];
  430. }].toArray.mutableCopy;
  431. if (sortChapterArr.count > 0) {
  432. [multipleChoiceArr replaceObjectAtIndex:[multipleChoiceArr indexOfObject:sortChapterArr.lastObject] withObject:difficultQuestionModel];
  433. }
  434. }
  435. } completed:^{
  436. /// Key: 按照排序的key; ascending: YES为升序, NO为降序。
  437. NSSortDescriptor *strTppeSorter = [[NSSortDescriptor alloc] initWithKey:@"chapter_id" ascending:YES];
  438. // NSSortDescriptor *diff_degreeSorter = [NSSortDescriptor sortDescriptorWithKey:@"diff_degree" ascending:YES];
  439. NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:strTppeSorter, nil];
  440. [arr addObjectsFromArray:[judgeArr sortedArrayUsingDescriptors:sortDescriptors]];
  441. [arr addObjectsFromArray:[choiceArr sortedArrayUsingDescriptors:sortDescriptors]];
  442. [arr addObjectsFromArray:[multipleChoiceArr sortedArrayUsingDescriptors:sortDescriptors]];
  443. dispatch_semaphore_signal(sema);
  444. }];
  445. dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
  446. return arr.copy;
  447. }] map:^id _Nullable(NSArray *examArr) {
  448. return examArr;
  449. }].toArray firstObject];
  450. return arr.copy;
  451. } else if (pageType == RQHomeSubPageType_FreeTry) {
  452. queryStr = [NSString stringWithFormat:@"SELECT * FROM question_info INNER JOIN question_free ON question_info.id = question_free.id AND question_free.subject = '%@' ORDER BY %@", [RQ_COMMON_MANAGER getSubjectTypeNumStrWithSubjectType:subject],(exerciseType == RQExerciseType_Random)? @"random()" : @"question_free.free_sort + 0 ASC"];
  453. return [self queryQuestionWithQueryStr:queryStr exerciseType:exerciseType];
  454. } else if (pageType == RQHomeSubPageType_MockExamination && exerciseType == RQExerciseType_MiExam) {
  455. queryStr = [NSString stringWithFormat:@"SELECT * FROM (SELECT * FROM question_info AS a JOIN (SELECT id_ydt, MAX(id) AS id FROM question_info GROUP BY id_ydt) AS t ON a.id = t.id) AS q JOIN t_app_question_category AS c ON q.id_ydt = c.question_id AND c.kemu = %@ AND c.gs = '%@' AND c.category = %@ ORDER BY c.sort_order + 0 ASC", [RQ_COMMON_MANAGER getSubjectTypeNumStrWithSubjectType:subject],[RQ_COMMON_MANAGER getCarTypeSimpleCNStrWithCarType:carType],[RQ_COMMON_MANAGER getMiExamTypeNumStrWithMiExamType:RQ_COMMON_MANAGER.miExamType]];
  456. return [self queryQuestionWithQueryStr:queryStr];
  457. } else {
  458. return [self queryQuestionWithQueryStr:queryStr exerciseType:exerciseType];
  459. }
  460. }
  461. - (RQExerciseModel *)getQuestionWithQuestionId:(NSInteger )questionId {
  462. __block RQExerciseModel *exerciseModel;
  463. if (_databaseQueue) {
  464. [_databaseQueue inDatabase:^(FMDatabase * _Nonnull db) {
  465. exerciseModel = [self getQuestionWithDataBase:db questionId:questionId];
  466. }];
  467. }
  468. return exerciseModel;
  469. }
  470. - (void)getQuestionsWithQuestionIdArr:(NSArray *)questionIdArr complete:(VoidBlock_id)complete {
  471. NSMutableArray *arr = @[].mutableCopy;
  472. if (_databaseQueue) {
  473. [_databaseQueue inTransaction:^(FMDatabase * _Nonnull db, BOOL * _Nonnull rollback) {
  474. @try {
  475. [questionIdArr.rac_sequence.signal subscribeNext:^(NSString *questionIdStr) {
  476. RQExerciseModel *exerciseModel = [self getQuestionWithDataBase:db questionId:questionIdStr.integerValue];
  477. [arr addObject:exerciseModel];
  478. } completed:^{
  479. if (complete) {
  480. complete(arr.copy);
  481. }
  482. }];
  483. } @catch (NSException *exception) {
  484. *rollback = YES;
  485. } @finally {
  486. *rollback = NO;
  487. }
  488. }];
  489. }
  490. }
  491. #pragma mark - Private Method
  492. - (NSArray *)queryQuestionWithQueryStr:(NSString *)queryStr exerciseType:(RQExerciseType)exerciseType {
  493. NSMutableArray *arr = @[].mutableCopy;
  494. if (_databaseQueue) {
  495. [_databaseQueue inDatabase:^(FMDatabase * _Nonnull db) {
  496. FMResultSet *resultSet;
  497. resultSet = [db executeQuery:queryStr];
  498. while ([resultSet next]) {
  499. RQExerciseModel *exerciseModel = [RQExerciseModel exerciseModelWithFMResultSet:resultSet];
  500. if (exerciseType == RQExerciseType_Recitation) {
  501. exerciseModel.userAnswer = exerciseModel.answer;
  502. }
  503. [arr addObject:exerciseModel];
  504. }
  505. }];
  506. }
  507. return arr.copy;
  508. }
  509. - (NSArray *)queryQuestionWithQueryStr:(NSString *)queryStr {
  510. NSMutableArray *arr = @[].mutableCopy;
  511. if (_databaseQueue) {
  512. [_databaseQueue inDatabase:^(FMDatabase * _Nonnull db) {
  513. FMResultSet *resultSet;
  514. resultSet = [db executeQuery:queryStr];
  515. while ([resultSet next]) {
  516. RQExerciseModel *exerciseModel = [RQExerciseModel exerciseModelWithFMResultSet:resultSet];
  517. [arr addObject:exerciseModel];
  518. }
  519. }];
  520. }
  521. return arr.copy;
  522. }
  523. - (NSString *)getQuestionNumQueryStrWithCarType:(RQHomePageCarType)carType subject:(RQHomePageSubjectType)subject questionType:(RQQuestionType)questionType isNew:(BOOL)isNew {
  524. switch (subject) {
  525. case RQHomePageSubjectType_SubjectOne: {
  526. switch (questionType) {
  527. case RQQuestionType_Judgment: {
  528. switch (carType) {
  529. case RQHomePageCarType_Car:
  530. return isNew? @"random() limit 20" : @"random() limit 20";
  531. case RQHomePageCarType_Bus:
  532. return isNew? @"random() limit 20" : @"random() limit 20";
  533. case RQHomePageCarType_Truck:
  534. return isNew? @"random() limit 20" : @"random() limit 20";
  535. case RQHomePageCarType_Motorcycle:
  536. return isNew? @"random() limit 10" : @"random() limit 10";
  537. default:
  538. return isNew? @"random() limit 20" : @"random() limit 20";
  539. }
  540. }
  541. case RQQuestionType_SingleChoice: {
  542. switch (carType) {
  543. case RQHomePageCarType_Car:
  544. return isNew? @"random() limit 10" : @"random() limit 50";
  545. case RQHomePageCarType_Bus:
  546. return isNew? @"random() limit 10" : @"random() limit 50";
  547. case RQHomePageCarType_Truck:
  548. return isNew? @"random() limit 10" : @"random() limit 50";
  549. case RQHomePageCarType_Motorcycle:
  550. return isNew? @"random() limit 5" : @"random() limit 25";
  551. default:
  552. return isNew? @"random() limit 10" : @"random() limit 50";
  553. }
  554. }
  555. case RQQuestionType_MultipleChoice: {
  556. switch (carType) {
  557. case RQHomePageCarType_Car:
  558. return @"random() limit 0";
  559. case RQHomePageCarType_Bus:
  560. return @"random() limit 0";
  561. case RQHomePageCarType_Truck:
  562. return @"random() limit 0";
  563. case RQHomePageCarType_Motorcycle:
  564. return @"random() limit 0";
  565. default:
  566. return @"random() limit 0";
  567. }
  568. }
  569. }
  570. }
  571. case RQHomePageSubjectType_SubjectFour: {
  572. switch (questionType) {
  573. case RQQuestionType_Judgment: {
  574. switch (carType) {
  575. case RQHomePageCarType_Car:
  576. return @"random() limit 10";
  577. case RQHomePageCarType_Bus:
  578. return @"random() limit 10";
  579. case RQHomePageCarType_Truck:
  580. return @"random() limit 10";
  581. case RQHomePageCarType_Motorcycle:
  582. return @"random() limit 10";
  583. default:
  584. return @"random() limit 10";
  585. }
  586. }
  587. case RQQuestionType_SingleChoice: {
  588. switch (carType) {
  589. case RQHomePageCarType_Car:
  590. return @"random() limit 10";
  591. case RQHomePageCarType_Bus:
  592. return @"random() limit 10";
  593. case RQHomePageCarType_Truck:
  594. return @"random() limit 10";
  595. case RQHomePageCarType_Motorcycle:
  596. return @"random() limit 10";
  597. default:
  598. return @"random() limit 10";
  599. }
  600. }
  601. case RQQuestionType_MultipleChoice: {
  602. switch (carType) {
  603. case RQHomePageCarType_Car:
  604. return @"random() limit 5";
  605. case RQHomePageCarType_Bus:
  606. return @"random() limit 5";
  607. case RQHomePageCarType_Truck:
  608. return @"random() limit 5";
  609. case RQHomePageCarType_Motorcycle:
  610. return @"random() limit 5";
  611. default:
  612. return @"random() limit 5";
  613. }
  614. }
  615. }
  616. }
  617. default:
  618. return @"random() limit 5";
  619. }
  620. }
  621. - (RQExerciseModel *)getQuestionWithDataBase:(FMDatabase *)dataBase questionId:(NSInteger )questionId {
  622. RQExerciseModel *exerciseModel;
  623. FMResultSet *resultSet;
  624. resultSet = [dataBase executeQuery:[NSString stringWithFormat:@"select * from question_info where id = %ld", questionId]];
  625. while ([resultSet next]) {
  626. exerciseModel = [RQExerciseModel exerciseModelWithFMResultSet:resultSet];
  627. }
  628. return exerciseModel;
  629. }
  630. - (NSInteger)getQuestionVersion {
  631. __block NSInteger version = 0;
  632. if (_databaseQueue) {
  633. [_databaseQueue inDatabase:^(FMDatabase * _Nonnull db) {
  634. FMResultSet *resultSet;
  635. resultSet = [db executeQuery:@"select version_num from question_version"];
  636. while ([resultSet next]) {
  637. version = [resultSet longLongIntForColumn:@"version_num"];
  638. }
  639. }];
  640. }
  641. return version;
  642. }
  643. - (NSInteger)getQuestionVersionWithResourcePath:(NSString *)resourcePath {
  644. __block NSInteger version = 0;
  645. [[FMDatabaseQueue databaseQueueWithPath:resourcePath] inDatabase:^(FMDatabase * _Nonnull db) {
  646. FMResultSet *resultSet;
  647. resultSet = [db executeQuery:@"SELECT version_num FROM question_version"];
  648. while ([resultSet next]) {
  649. version = [resultSet longLongIntForColumn:@"version_num"];
  650. }
  651. }];
  652. return version;
  653. }
  654. - (NSArray *)getExamRuleWithCarType:(RQHomePageCarType)carType subject:(RQHomePageSubjectType)subject {
  655. NSString *queryCarTypeStr = [NSString stringWithFormat:@"gs LIKE '%%%@%%'",[RQ_COMMON_MANAGER getCarTypeSimpleCNStrWithCarType:carType]];
  656. NSString *querySubjectTypeStr = [NSString stringWithFormat:@"kemu = '%@'",[RQ_COMMON_MANAGER getSubjectTypeNumStrWithSubjectType:subject]];
  657. NSString *examRuleTableName = @"t_app_exam_rule";
  658. NSString *queryStr = [NSString stringWithFormat:@"SELECT * FROM %@ WHERE %@ AND %@ AND areacode = 0 ", examRuleTableName, queryCarTypeStr, querySubjectTypeStr];
  659. return [self queryExamRuleWithQueryStr:queryStr];
  660. }
  661. - (NSArray *)queryExamRuleWithQueryStr:(NSString *)queryStr {
  662. NSMutableArray *arr = @[].mutableCopy;
  663. if (_databaseQueue) {
  664. [_databaseQueue inDatabase:^(FMDatabase * _Nonnull db) {
  665. FMResultSet *resultSet;
  666. resultSet = [db executeQuery:queryStr];
  667. while ([resultSet next]) {
  668. RQExamRuleModel *examRuleModel = [RQExamRuleModel sdjkExamRuleModelWithFMResultSet:resultSet];
  669. [arr addObject:examRuleModel];
  670. }
  671. }];
  672. }
  673. return arr.copy;
  674. }
  675. - (RQExplainModel *)getExplainWithExerciseModel:(RQExerciseModel *)exerciseModel {
  676. __block RQExplainModel *explainModel;
  677. if (_databaseQueue) {
  678. [_databaseQueue inDatabase:^(FMDatabase * _Nonnull db) {
  679. FMResultSet *resultSet;
  680. NSString *queryStr = [NSString stringWithFormat:@"SELECT * FROM %@ WHERE questionIds = %ld", @"question_sd_js", (long)exerciseModel.id_ydt];
  681. resultSet = [db executeQuery:queryStr];
  682. while ([resultSet next]) {
  683. explainModel = [RQExplainModel questionExplainWithFMResultSet:resultSet];
  684. }
  685. }];
  686. }
  687. return explainModel;
  688. }
  689. @end